Skip to content

Commit

Permalink
use synchronous REPLs throughout; use proper name and API roles for t…
Browse files Browse the repository at this point in the history
…his too!
  • Loading branch information
jrockway committed Jun 8, 2010
1 parent 523c79f commit 9a50f98
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 84 deletions.
70 changes: 35 additions & 35 deletions lib/Stylish/REPL/Project.pm
@@ -1,9 +1,10 @@
use MooseX::Declare;

class Stylish::REPL::Project {
class Stylish::REPL::Project
with (AnyEvent::REPL::API::Sync, AnyEvent::REPL::API::Async) {
use Stylish::Project;
use AnyEvent::REPL;
use AnyEvent::REPL::Types qw(REPL);
use AnyEvent::REPL::Types qw(SyncREPL AsyncREPL);
use AnyEvent::REPL::CoroWrapper;
use AnyEvent::Debounce;
use Coro;
Expand Down Expand Up @@ -31,7 +32,8 @@ class Stylish::REPL::Project {

has 'good_repl' => (
is => 'rw',
isa => REPL,
isa => SyncREPL,
handles => 'AnyEvent::REPL::API::Sync',
lazy_build => 1,
);

Expand Down Expand Up @@ -78,50 +80,63 @@ class Stylish::REPL::Project {

method _build_good_repl {
my $r = $self->make_repl;
async { $self->_setup_repl_pwd($r) }->join;
$self->_setup_repl_pwd($r);
return $r;
}

method repl_eval(REPL $repl, Str $code) {
my @result = $repl->do_eval($code, on_output => $self->on_output);
return @result if wantarray;
return join '', @result;
around do_eval(@args){
my $result = $self->$orig(@args);
chomp $result;
return $result;
}

method push_eval(@args) {
my $good_repl = $self->good_repl;
return $good_repl->can('push_eval') ?
$good_repl->push_eval(@args) :
$good_repl->repl->push_eval(@args);
}

method repl_command(REPL $repl, Str $command, HashRef $args) {
return $repl->do_command($command, $args);
method push_command(@args) {
my $good_repl = $self->good_repl;
return $good_repl->can('push_command') ?
$good_repl->push_command(@args) :
$good_repl->repl->push_command(@args);
}

method _setup_repl_pwd(REPL $repl){

after kill { $self->change }

method _setup_repl_pwd(SyncREPL $repl){
my $dir = $self->project->root->resolve->absolute;
my $lib = $dir->subdir('lib');
$self->repl_eval($repl, qq{chdir "\Q$dir\E";});
$self->repl_eval($repl, qq{use lib "\Q$lib\E"});
$repl->do_eval(qq{chdir "\Q$dir\E";});
$repl->do_eval(qq{use lib "\Q$lib\E"});
}

method _load_modules_in_repl(REPL $repl, Bool $strict_load? = 1){
method _load_modules_in_repl(SyncREPL $repl, Bool $strict_load? = 1){
my @modules = $self->project->get_libraries;
my $error = 'unknown error';
my $result = eval {
$self->_setup_repl_pwd($repl);
if ($strict_load) {
$self->repl_eval($repl, qq{require "\Q$_\E"}) for @modules;
$repl->do_eval(qq{require "\Q$_\E"}) for @modules;
}
else {
$self->repl_eval($repl, qq{eval { require "\Q$_\E" }}) for @modules;
$repl->do_eval(qq{eval { require "\Q$_\E" }}) for @modules;
}
return $self->repl_eval($repl, qq{2 + 2});
return $repl->do_eval(qq{2 + 2});
};
$error = $@ if $@;
return $repl if defined $result && $result eq '4';
die "Modules failed to load in the new REPL: $error";
}

method _transfer_lexenv(REPL $from, REPL $to){
method _transfer_lexenv(SyncREPL $from, SyncREPL $to){
my ($fh, $filename) = tempfile();

$self->repl_command($from, 'save_state', { filename => $filename });
$self->repl_command($to, 'restore_state', { filename => $filename });
$from->do_command( 'save_state', { filename => $filename } );
$to->do_command( 'restore_state', { filename => $filename } );

close $fh;
unlink $filename;
Expand All @@ -147,20 +162,5 @@ class Stylish::REPL::Project {
};
}

method do_eval(Str $code, Bool $chomp? = 1){
my $result = $self->repl_eval($self->good_repl, $code);
chomp $result if $chomp;
return $result;
}

method push_eval(@args){
$self->good_repl->push_eval(@args);
}

method BUILD { $self->change }

method kill(Int $num? = 9) {
$self->good_repl->kill($num);
$self->change;
}
}
38 changes: 25 additions & 13 deletions lib/Stylish/Server/Component/REPL.pm
Expand Up @@ -2,12 +2,14 @@ use MooseX::Declare;

class Stylish::Server::Component::REPL with Stylish::Server::Component {
use MooseX::Types::Moose qw(Str Maybe HashRef Int);
use Stylish::Types qw(REPL);
use AnyEvent::REPL::Types qw(SyncREPL);
use AnyEvent::REPL;
use AnyEvent::REPL::CoroWrapper;
use Try::Tiny;

has 'repls' => (
is => 'ro',
isa => HashRef[REPL],
isa => HashRef[SyncREPL],
default => sub { +{} },
traits => ['Hash'],
handles => {
Expand All @@ -19,6 +21,15 @@ class Stylish::Server::Component::REPL with Stylish::Server::Component {
},
);

around add_repl(Str $name, $repl){
return $self->$orig(
$name,
$repl->does('AnyEvent::REPL::API::Async')
? AnyEvent::REPL::CoroWrapper->new( repl => $repl )
: $repl,
);
}

before get_repl(Str $repl_name){
# make REPLs auto-vivify
$self->add_repl($repl_name, AnyEvent::REPL->new)
Expand Down Expand Up @@ -69,19 +80,20 @@ class Stylish::Server::Component::REPL with Stylish::Server::Component {
method repl_eval(Str :$name, Str :$code, CodeRef :$response_cb){
my $repl = $self->get_repl($name);

my $done = Coro::rouse_cb;
my $is_success = 0;
$repl->push_eval(
$code,
on_error => $done,
on_result => sub { $is_success = 1; $done->(@_) },
on_output => sub { $response_cb->('repl_output', {
data => join('', @_),
repl => $name,
})},
);
my $result = try {
my $r = $repl->do_eval(
$code,
on_output => sub { $response_cb->('repl_output', {
data => join('', @_),
repl => $name,
})},
);
$is_success = 1;
return $r;
} catch { $_ };

return { success => $is_success, result => join('', Coro::rouse_wait) };
return { success => $is_success, result => $result };
}

method write_stdin(Str :$name, Str :$input){
Expand Down
9 changes: 2 additions & 7 deletions lib/Stylish/Test/REPL.pm
@@ -1,6 +1,6 @@
use MooseX::Declare;

class Stylish::Test::REPL {
class Stylish::Test::REPL with AnyEvent::REPL::API::Sync {
use Stylish::Test::Recorder;
use Coro;
use Storable;
Expand Down Expand Up @@ -56,19 +56,14 @@ class Stylish::Test::REPL {
return Stylish::Test::Recorder->new;
}

method push_eval(Str $code, CodeRef :$on_output?){
$on_output ||= sub {};
return $self->do_eval($code, on_output => $on_output);
}

method test_eval(Str $code, CodeRef :$on_output?){
$on_output ||= sub {};

my ($fh, $filename) = tempfile();
$self->do_command( save_state => { filename => $filename } );
my $lexenv = retrieve($filename)->{context}{_};

my $result = $self->push_eval($code, on_output => $on_output);
my $result = $self->do_eval($code, on_output => $on_output);
$self->do_one_test($lexenv, $code, $result);
return $result;
}
Expand Down
38 changes: 14 additions & 24 deletions lib/Stylish/Test/Writer/Run.pm
@@ -1,19 +1,18 @@
use MooseX::Declare;

# export test script to eval'd TAP
class Stylish::Test::Writer::Run {
class Stylish::Test::Writer::Run with AnyEvent::REPL::API::Sync {
use AnyEvent::REPL;
use Stylish::Types qw(REPL);
use AnyEvent::REPL::Types qw(SyncREPL);
use Coro::Util::Rouse qw(rouse_cb rouse_wait);
use TAP::Parser;

has 'repl' => (
is => 'ro',
isa => REPL,
isa => SyncREPL,
lazy_build => 1,
handles => {
_push_eval => 'push_eval',
},
coerce => 1,
handles => 'AnyEvent::REPL::API::Sync',
);

has 'tap_accumulator' => (
Expand All @@ -34,22 +33,13 @@ class Stylish::Test::Writer::Run {
$self->run_use_command('Test::More');
}

method push_eval(Str $code){
my ($ok, $err) = rouse_cb;
# print "# $code\n";
$self->_push_eval(
$code,
on_output => sub { $self->accumulate_tap( $_[0] ) if $_[0] },
on_error => $err,
on_result => $ok,
);

return rouse_wait;
around do_eval(@args){
$self->$orig(@args, on_output => sub { $self->accumulate_tap($_[0]) });
}

method run(ArrayRef $script){
$self->push_eval('delete $_REPL->{lexical_environment}');
$self->push_eval('Test::Builder->new->reset');
$self->do_eval('delete $_REPL->{lexical_environment}');
$self->do_eval('Test::Builder->new->reset');
$self->clear_tap_accumulator;

for my $step (@$script) {
Expand All @@ -58,7 +48,7 @@ class Stylish::Test::Writer::Run {
$self->run_command(@$step);
}

$self->push_eval('done_testing');
$self->do_eval('done_testing');

my $parser = TAP::Parser->new({
tap => $self->captured_tap,
Expand All @@ -82,18 +72,18 @@ class Stylish::Test::Writer::Run {

method run_use_command(Str $module, Str $args?){
$args ||= "";
$self->push_eval("use $module $args");
$self->do_eval("use $module $args");
}

method run_bind_command(Str $var, Any $val) {
$self->push_eval("my $var = ". $self->escape_for_eval($val));
$self->do_eval("my $var = ". $self->escape_for_eval($val));
}

method run_set_command(Str $var, Any $val) {
$self->push_eval("$var = ". $self->escape_for_eval($val));
$self->do_eval("$var = ". $self->escape_for_eval($val));
}

method run_test_command(Str $got_var, Any $expected) {
$self->push_eval("is_deeply $got_var, ". $self->escape_for_eval($expected));
$self->do_eval("is_deeply $got_var, ". $self->escape_for_eval($expected));
}
}
4 changes: 1 addition & 3 deletions lib/Stylish/Types.pm
Expand Up @@ -2,14 +2,12 @@ package Stylish::Types;
use strict;
use warnings;

use MooseX::Types -declare => [qw/REPL Type Command Component Components/];
use MooseX::Types -declare => [qw/Type Command Component Components/];
use MooseX::Types::Moose qw(CodeRef HashRef ArrayRef Str Object);
use MooseX::Types::Structured qw(Dict Optional);

class_type Type, { class => 'Moose::Meta::TypeConstraint' };

duck_type REPL, ['push_eval'];

subtype Command, as Dict[
name => Str,
args => Optional[HashRef[Type]],
Expand Down
2 changes: 1 addition & 1 deletion t/components/repl.t
Expand Up @@ -8,7 +8,7 @@ use Stylish::Server::Component::REPL;
my $repls = Stylish::Server::Component::REPL->new;

async {
isa_ok $repls->get_repl('test'), 'AnyEvent::REPL';
isa_ok $repls->get_repl('test'), 'AnyEvent::REPL::CoroWrapper';
is_deeply $repls->repl_eval(
name => 'new_repl',
code => '2 + 2',
Expand Down
2 changes: 1 addition & 1 deletion t/test/recorder-repl.t
Expand Up @@ -10,7 +10,7 @@ my $repl = Stylish::Test::REPL->new;
ok $repl;

async {
$repl->push_eval('my $foo = 42');
$repl->do_eval('my $foo = 42');
$repl->test_eval('$foo + 1');
$repl->test_eval('$foo == 42');
}->join;
Expand Down

0 comments on commit 9a50f98

Please sign in to comment.