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