Commit | Line | Data |
afe61f9c |
1 | package Devel::REPL; |
2 | |
3 | use Term::ReadLine; |
4 | use Moose; |
aa8b7647 |
5 | use namespace::autoclean; |
089a0c4e |
6 | use 5.008001; # backwards compat, doesn't warn like 5.8.1 |
59aedffc |
7 | |
afe61f9c |
8 | with 'MooseX::Object::Pluggable'; |
9 | |
e22aa835 |
10 | use Devel::REPL::Error; |
11 | |
afe61f9c |
12 | has 'term' => ( |
b595a818 |
13 | is => 'rw', |
2df2b90e |
14 | lazy => 1, |
afe61f9c |
15 | default => sub { Term::ReadLine->new('Perl REPL') } |
16 | ); |
17 | |
18 | has 'prompt' => ( |
b595a818 |
19 | is => 'rw', |
afe61f9c |
20 | default => sub { '$ ' } |
21 | ); |
22 | |
23 | has 'out_fh' => ( |
b595a818 |
24 | is => 'rw', |
25 | lazy => 1, |
afe61f9c |
26 | default => sub { shift->term->OUT || \*STDOUT; } |
27 | ); |
28 | |
57719095 |
29 | has 'exit_repl' => ( |
b595a818 |
30 | is => 'rw', |
57719095 |
31 | default => sub { 0 } |
32 | ); |
33 | |
afe61f9c |
34 | sub run { |
35 | my ($self) = @_; |
e22aa835 |
36 | while ($self->run_once_safely) { |
57719095 |
37 | # keep looping unless we want to exit REPL |
38 | last if $self->exit_repl; |
afe61f9c |
39 | } |
40 | } |
41 | |
e22aa835 |
42 | sub run_once_safely { |
43 | my ($self, @args) = @_; |
44 | |
45 | my $ret = eval { $self->run_once(@args) }; |
46 | |
47 | if ($@) { |
48 | my $error = $@; |
49 | eval { $self->print("Error! - $error\n"); }; |
50 | return 1; |
51 | } else { |
52 | return $ret; |
53 | } |
54 | } |
55 | |
afe61f9c |
56 | sub run_once { |
57 | my ($self) = @_; |
e22aa835 |
58 | |
afe61f9c |
59 | my $line = $self->read; |
57719095 |
60 | return unless defined($line); # undefined value == EOF |
e22aa835 |
61 | |
62 | my @ret = $self->formatted_eval($line); |
63 | |
57719095 |
64 | $self->print(@ret) unless $self->exit_repl; |
e22aa835 |
65 | |
afe61f9c |
66 | return 1; |
67 | } |
68 | |
e22aa835 |
69 | sub formatted_eval { |
70 | my ( $self, @args ) = @_; |
71 | |
72 | my @ret = $self->eval(@args); |
73 | |
74 | return $self->format(@ret); |
75 | } |
76 | |
77 | sub format { |
78 | my ( $self, @stuff ) = @_; |
79 | |
c3bbf326 |
80 | if ( $self->is_error($stuff[0]) ) { |
e22aa835 |
81 | return $self->format_error(@stuff); |
82 | } else { |
83 | return $self->format_result(@stuff); |
84 | } |
85 | } |
86 | |
87 | sub format_result { |
88 | my ( $self, @stuff ) = @_; |
89 | |
90 | return @stuff; |
91 | } |
92 | |
93 | sub format_error { |
94 | my ( $self, $error ) = @_; |
95 | return $error->stringify; |
96 | } |
97 | |
c3bbf326 |
98 | sub is_error { |
99 | my ( $self, $thingy ) = @_; |
100 | blessed($thingy) and $thingy->isa("Devel::REPL::Error"); |
101 | } |
102 | |
afe61f9c |
103 | sub read { |
104 | my ($self) = @_; |
105 | return $self->term->readline($self->prompt); |
106 | } |
107 | |
911a1c24 |
108 | sub eval { |
109 | my ($self, $line) = @_; |
c3bbf326 |
110 | my $compiled = $self->compile($line); |
111 | return $compiled unless defined($compiled) and not $self->is_error($compiled); |
112 | return $self->execute($compiled); |
911a1c24 |
113 | } |
114 | |
115 | sub compile { |
e22aa835 |
116 | my ( $_REPL, @args ) = @_; |
117 | my $compiled = eval $_REPL->wrap_as_sub(@args); |
c3bbf326 |
118 | return $_REPL->error_return("Compile error", $@) if $@; |
911a1c24 |
119 | return $compiled; |
120 | } |
121 | |
122 | sub wrap_as_sub { |
e22aa835 |
123 | my ($self, $line, %args) = @_; |
124 | return qq!sub {\n!. ( $args{no_mangling} ? $line : $self->mangle_line($line) ).qq!\n}\n!; |
911a1c24 |
125 | } |
126 | |
127 | sub mangle_line { |
128 | my ($self, $line) = @_; |
129 | return $line; |
130 | } |
131 | |
afe61f9c |
132 | sub execute { |
48ddfeae |
133 | my ($self, $to_exec, @args) = @_; |
134 | my @ret = eval { $to_exec->(@args) }; |
135 | return $self->error_return("Runtime error", $@) if $@; |
afe61f9c |
136 | return @ret; |
137 | } |
138 | |
911a1c24 |
139 | sub error_return { |
140 | my ($self, $type, $error) = @_; |
e22aa835 |
141 | return Devel::REPL::Error->new( type => $type, message => $error ); |
911a1c24 |
142 | } |
143 | |
afe61f9c |
144 | sub print { |
145 | my ($self, @ret) = @_; |
146 | my $fh = $self->out_fh; |
59aedffc |
147 | no warnings 'uninitialized'; |
afe61f9c |
148 | print $fh "@ret"; |
a66625d6 |
149 | print $fh "\n" if $self->term->ReadLine =~ /Gnu/; |
afe61f9c |
150 | } |
151 | |
59aedffc |
152 | =head1 NAME |
153 | |
eb7716dc |
154 | Devel::REPL - A modern perl interactive shell |
59aedffc |
155 | |
156 | =head1 SYNOPSIS |
157 | |
158 | my $repl = Devel::REPL->new; |
159 | $repl->load_plugin($_) for qw(History LexEnv); |
160 | $repl->run |
161 | |
162 | Alternatively, use the 're.pl' script installed with the distribution |
163 | |
950232b2 |
164 | system$ re.pl |
165 | |
408564af |
166 | =head1 DESCRIPTION |
167 | |
168 | This is an interactive shell for Perl, commonly known as a REPL - Read, |
169 | Evaluate, Print, Loop. The shell provides for rapid development or testing |
170 | of code without the need to create a temporary source code file. |
171 | |
172 | Through a plugin system, many features are available on demand. You can also |
173 | tailor the environment through the use of profiles and run control files, for |
174 | example to pre-load certain Perl modules when working on a particular project. |
175 | |
176 | =head1 USAGE |
177 | |
178 | To start a shell, follow one of the examples in the L</"SYNOPSIS"> above. |
179 | |
180 | Once running, the shell accepts and will attempt to execute any code given. If |
181 | the code executes successfully you'll be shown the result, otherwise an error |
182 | message will be returned. Here are a few examples: |
183 | |
184 | $_ print "Hello, world!\n" |
185 | Hello, world! |
186 | 1 |
187 | $_ nosuchfunction |
188 | Compile error: Bareword "nosuchfunction" not allowed while "strict subs" in use at (eval 130) line 5. |
20d9434d |
189 | |
190 | $_ |
408564af |
191 | |
192 | In the first example above you see the output of the command (C<Hello, |
193 | world!>), if any, and then the return value of the statement (C<1>). Following |
194 | that example, an error is returned when the execution of some code fails. |
195 | |
196 | Note that the lack of semicolon on the end is not a mistake - the code is |
197 | run inside a Block structure (to protect the REPL in case the code blows up), |
198 | which means a single statement doesn't require the semicolon. You can add one |
199 | if you like, though. |
200 | |
6aa58492 |
201 | If you followed the first example in the L</"SYNOPSIS"> above, you'll have the |
8d5343b5 |
202 | L<History|Devel::REPL::Plugin::History> and L<LexEnv|Devel::REPL::Plugin::LexEnv> |
203 | plugins loaded (and there are many more available). |
408564af |
204 | Although the shell might support "up-arrow" history, the History plugin adds |
205 | "bang" history to that so you can re-execute chosen commands (with e.g. |
206 | C<!53>). The LexEnv plugin ensures that lexical variables declared with the |
207 | C<my> keyword will automatically persist between statements executed in the |
208 | REPL shell. |
209 | |
210 | When you C<use> any Perl module, the C<import()> will work as expected - the |
211 | exported functions from that module are available for immediate use: |
212 | |
213 | $_ carp "I'm dieeeing!\n" |
214 | String found where operator expected at (eval 129) line 5, near "carp "I'm dieeeing!\n"" |
215 | (Do you need to predeclare carp?) |
216 | Compile error: syntax error at (eval 129) line 5, near "carp "I'm dieeeing!\n"" |
217 | BEGIN not safe after errors--compilation aborted at (eval 129) line 5. |
20d9434d |
218 | |
219 | $_ use Carp |
220 | |
408564af |
221 | $_ carp "I'm dieeeing!\n" |
222 | I'm dieeeing! |
223 | at /usr/share/perl5/Lexical/Persistence.pm line 327 |
224 | 1 |
20d9434d |
225 | $_ |
408564af |
226 | |
73d11b24 |
227 | To quit from the shell, hit C<Ctrl+D> or C<Ctrl+C>. |
228 | |
229 | MSWin32 NOTE: control keys won't work if TERM=dumb |
230 | because readline functionality will be disabled. |
231 | |
408564af |
232 | |
233 | =head2 Run Control Files |
234 | |
235 | For particular projects you might well end up running the same commands each |
236 | time the REPL shell starts up - loading Perl modules, setting configuration, |
237 | and so on. A run control file lets you have this done automatically, and you |
238 | can have multiple files for different projects. |
239 | |
240 | By default the C<re.pl> program looks for C<< $HOME/.re.pl/repl.rc >>, and |
241 | runs whatever code is in there as if you had entered it at the REPL shell |
242 | yourself. |
243 | |
244 | To set a new run control file that's also in that directory, pass it as a |
245 | filename like so: |
246 | |
247 | system$ re.pl --rcfile myproject.pc |
248 | |
0e0d2539 |
249 | If the filename happens to contain a forward slash, then it's used absolutely, |
408564af |
250 | or realive to the current working directory: |
251 | |
252 | system$ re.pl --rcfile /path/to/my/project/repl.rc |
253 | |
254 | Within the run control file you might want to load plugins. This is covered in |
255 | L</"The REPL shell object"> section, below. |
256 | |
257 | =head2 Profiles |
258 | |
259 | To allow for the sharing of run control files, you can fashion them into a |
260 | Perl module for distribution (perhaps via the CPAN). For more information on |
261 | this feature, please see the L<Devel::REPL::Profile> manual page. |
262 | |
e72070d7 |
263 | A C<Standard> profile ships with C<Devel::REPL>; it loads the following plugins |
264 | (note that some of these require optional features -- or you can also use the |
265 | C<Minimal> profile): |
408564af |
266 | |
267 | =over 4 |
268 | |
269 | =item * |
270 | |
271 | L<Devel::REPL::Plugin::History> |
272 | |
273 | =item * |
274 | |
275 | L<Devel::REPL::Plugin::LexEnv> |
276 | |
277 | =item * |
278 | |
279 | L<Devel::REPL::Plugin::DDS> |
280 | |
281 | =item * |
282 | |
283 | L<Devel::REPL::Plugin::Packages> |
284 | |
285 | =item * |
286 | |
287 | L<Devel::REPL::Plugin::Commands> |
288 | |
289 | =item * |
290 | |
291 | L<Devel::REPL::Plugin::MultiLine::PPI> |
292 | |
071c41fa |
293 | =item * |
294 | |
295 | L<Devel::REPL::Plugin::Colors> |
296 | |
297 | =item * |
298 | |
299 | L<Devel::REPL::Plugin::Completion> |
300 | |
301 | =item * |
302 | |
303 | L<Devel::REPL::Plugin::CompletionDriver::INC> |
304 | |
305 | =item * |
306 | |
307 | L<Devel::REPL::Plugin::CompletionDriver::LexEnv> |
308 | |
309 | =item * |
310 | |
311 | L<Devel::REPL::Plugin::CompletionDriver::Keywords> |
312 | |
313 | =item * |
314 | |
315 | L<Devel::REPL::Plugin::CompletionDriver::Methods> |
316 | |
317 | =item * |
318 | |
319 | L<Devel::REPL::Plugin::ReadlineHistory> |
320 | |
408564af |
321 | =back |
322 | |
323 | =head2 Plugins |
324 | |
0e0d2539 |
325 | Plugins are a way to add functionality to the REPL shell, and take advantage of |
408564af |
326 | C<Devel::REPL> being based on the L<Moose> object system for Perl 5. This |
327 | means it's simple to 'hook into' many steps of the R-E-P-L process. Plugins |
328 | can change the way commands are interpreted, or the way their results are |
329 | output, or even add commands to the shell environment. |
330 | |
331 | A number of plugins ship with C<Devel::REPL>, and more are available on the |
332 | CPAN. Some of the shipped plugins are loaded in the default profile, mentioned |
8d5343b5 |
333 | above. These plugins can be loaded in your F< $HOME/.re.pl/repl.rc > like: |
cfb85b27 |
334 | |
335 | load_plugin qw( CompletionDriver::Global DumpHistory ); |
408564af |
336 | |
337 | Writing your own plugins is not difficult, and is discussed in the |
338 | L<Devel::REPL::Plugin> manual page, along with links to the manual pages of |
339 | all the plugins shipped with C<Devel::REPL>. |
340 | |
341 | =head2 The REPL shell object |
342 | |
343 | From time to time you'll want to interact with or manipulate the |
344 | C<Devel::REPL> shell object itself; that is, the instance of the shell you're |
345 | currently running. |
346 | |
347 | The object is always available through the C<$_REPL> variable. One common |
348 | requirement is to load an additional plugin, after your profile and run |
349 | control files have already been executed: |
350 | |
351 | $_ $_REPL->load_plugin('Timing'); |
352 | 1 |
353 | $_ print "Hello again, world!\n" |
354 | Hello again, world! |
355 | Took 0.00148296356201172 seconds. |
356 | 1 |
357 | $_ |
358 | |
e72070d7 |
359 | =head1 OPTIONAL FEATURES |
408564af |
360 | |
e72070d7 |
361 | In addition to the prerequisites declared in this distribution, which should be automatically installed by your L<CPAN> client, there are a number of optional features, used by |
362 | additional plugins. You can install any of these features by installing this |
363 | distribution interactively (e.g. C<cpanm --interactive Devel::REPL>). |
408564af |
364 | |
e72070d7 |
365 | =for comment I hope to automatically generate this data via a Pod::Weaver section |
ab213f1f |
366 | |
367 | =over 4 |
368 | |
e72070d7 |
369 | =item * Completion plugin - extensible tab completion |
ab213f1f |
370 | |
e72070d7 |
371 | =item * DDS plugin - better format results with Data::Dump::Streamer |
408564af |
372 | |
e72070d7 |
373 | =item * DDC plugin - even better format results with Data::Dumper::Concise |
408564af |
374 | |
e72070d7 |
375 | =item * INC completion driver - tab complete module names in use and require |
408564af |
376 | |
e72070d7 |
377 | =item * Interrupt plugin - traps SIGINT to kill long-running lines |
408564af |
378 | |
e72070d7 |
379 | =item * Keywords completion driver - tab complete Perl keywords and operators |
73d11b24 |
380 | |
e72070d7 |
381 | =item * LexEnv plugin - variables declared with "my" persist between statements |
73d11b24 |
382 | |
e72070d7 |
383 | =item * MultiLine::PPI plugin - continue reading lines until all blocks are closed |
408564af |
384 | |
e72070d7 |
385 | =item * Nopaste plugin - upload a session\'s input and output to a Pastebin |
408564af |
386 | |
e72070d7 |
387 | =item * PPI plugin - PPI dumping of Perl code |
ab213f1f |
388 | |
e72070d7 |
389 | =item * Refresh plugin - automatically reload libraries with Module::Refresh |
ab213f1f |
390 | |
408564af |
391 | =back |
392 | |
59aedffc |
393 | =head1 AUTHOR |
394 | |
395 | Matt S Trout - mst (at) shadowcatsystems.co.uk (L<http://www.shadowcatsystems.co.uk/>) |
396 | |
c1d5d500 |
397 | =head1 CONTRIBUTORS |
398 | |
399 | =over 4 |
400 | |
401 | =item Stevan Little - stevan (at) iinteractive.com |
402 | |
403 | =item Alexis Sukrieh - sukria+perl (at) sukria.net |
404 | |
405 | =item epitaph |
406 | |
407 | =item mgrimes - mgrimes (at) cpan dot org |
408 | |
409 | =item Shawn M Moore - sartak (at) gmail.com |
410 | |
ab213f1f |
411 | =item Oliver Gorwits - oliver on irc.perl.org |
6aa58492 |
412 | |
da4881b1 |
413 | =item Andrew Moore - C<< <amoore@cpan.org> >> |
414 | |
88d6bf36 |
415 | =item Norbert Buchmuller C<< <norbi@nix.hu> >> |
416 | |
d13037d5 |
417 | =item Dave Houston C<< <dhouston@cpan.org> >> |
418 | |
73d11b24 |
419 | =item Chris Marshall |
420 | |
b28cbcb7 |
421 | =item Karen Etheridge C<< <ether@cpan.org> >> |
422 | |
c1d5d500 |
423 | =back |
424 | |
59aedffc |
425 | =head1 LICENSE |
426 | |
427 | This library is free software under the same terms as perl itself |
428 | |
429 | =cut |
430 | |
afe61f9c |
431 | 1; |