Move to Moo for fast bootstrapping.
[p5sagit/Devel-REPL.git] / lib / Devel / REPL / Plugin / OutputCache.pm
1 package Devel::REPL::Plugin::OutputCache;
2
3 use Devel::REPL::Plugin;
4 use namespace::sweep;
5 use MooX::Types::MooseLike::Base qw(ArrayRef Bool);
6
7 has output_cache => (
8     is      => 'rw',
9     isa     => ArrayRef,
10     default => sub { [] },
11     lazy    => 1,
12 );
13
14 has warned_about_underscore => (
15     is      => 'rw',
16     isa     => Bool,
17     default => sub { 0 },
18     lazy    => 1,
19 );
20
21 around 'eval' => sub {
22     my $orig = shift;
23     my ($self, $line) = @_;
24
25     my $has_underscore = *_{CODE};
26     if ($has_underscore && !$self->warned_about_underscore) {
27         warn "OutputCache: Sub _ already defined.";
28         $self->warned_about_underscore(1);
29     }
30     else {
31         # if _ is removed, then we should warn about it again if it comes back
32         $self->warned_about_underscore(0);
33     }
34
35     # this needs to be a postfix conditional for 'local' to work
36     local *_ = sub () { $self->output_cache->[-1] } unless $has_underscore;
37
38     my @ret;
39     if (wantarray) {
40         @ret = $self->$orig($line);
41     }
42     else {
43         $ret[0] = $self->$orig($line);
44     }
45
46     push @{ $self->output_cache }, @ret > 1 ? \@ret : $ret[0];
47     return wantarray ? @ret : $ret[0];
48 };
49
50 1;
51
52 __END__
53
54 =head1 NAME
55
56 Devel::REPL::Plugin::OutputCache - remember past results, _ is most recent
57
58 =head1 SYNOPSIS
59
60     > 21 / 7
61     3
62     > _ * _
63     9
64     > sub { die "later" }
65     sub { die "later" }
66     > _->()
67     Runtime error: later
68
69 =head1 DESCRIPTION
70
71 Re-using results is very useful when working in a REPL. With C<OutputCache> you
72 get C<_>, which holds the past result. The benefit is that you can build up
73 your result instead of having to type it in all at once, or store it in
74 intermediate variables. C<OutputCache> also provides
75 C<< $_REPL->output_cache >>, an array reference of all results in this session.
76
77 Devel::REPL already has a similar plugin, L<Devel::REPL::Plugin::History>.
78 There are some key differences though:
79
80 =over 4
81
82 =item Input vs Output
83
84 C<History> remembers input. C<OutputCache> remembers output.
85
86 =item Munging vs Pure Perl
87
88 C<History> performs regular expressions on your input. C<OutputCache> provides
89 the C<_> sub as a hook to get the most recent result, and
90 C<< $_REPL->output_cache >> for any other results.
91
92 =item Principle of Least Surprise
93
94 C<History> will replace exclamation points in any part of the input. This is
95 problematic if you accidentally include one in a string, or in a C<not>
96 expression. C<OutputCache> uses a regular (if oddly named) subroutine so Perl
97 does the parsing -- no surprises.
98
99 =back
100
101 =head1 CAVEATS
102
103 The C<_> sub is shared across all packages. This means that if a module is
104 using the C<_> sub, then there is a conflict and you should not use this
105 plugin. For example, L<Jifty> uses the C<_> sub for localization. Jifty is the
106 only known user.
107
108 =head1 SEE ALSO
109
110 C<Devel::REPL>, C<Devel::REPL::Plugin::History>
111
112 =head1 AUTHOR
113
114 Shawn M Moore, C<< <sartak at gmail dot com> >>
115
116 =head1 COPYRIGHT AND LICENSE
117
118 Copyright (C) 2007 by Shawn M Moore
119
120 This library is free software; you can redistribute it and/or modify
121 it under the same terms as Perl itself.
122
123 =cut