summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2013-06-03 15:18:17 -0500
committerJesse Luehrs <doy@tozt.net>2013-06-03 15:51:17 -0500
commitec069554b263d4d3a60a315089e170b92badd1d8 (patch)
tree38e4b6cb2196ee0b56aa33c29df3a94c53ad1e20
parent60f235d03fba8232e7f691550ee715e1cfb9c5b6 (diff)
downloadreply-ec069554b263d4d3a60a315089e170b92badd1d8.tar.gz
reply-ec069554b263d4d3a60a315089e170b92badd1d8.zip
start on some docs
-rw-r--r--bin/reply16
-rw-r--r--lib/Reply.pm122
-rw-r--r--lib/Reply/Plugin.pm117
-rw-r--r--lib/Reply/Plugin/Colors.pm20
-rw-r--r--lib/Reply/Plugin/DataDump.pm12
-rw-r--r--lib/Reply/Plugin/DataDumper.pm12
-rw-r--r--lib/Reply/Plugin/Editor.pm20
-rw-r--r--lib/Reply/Plugin/FancyPrompt.pm14
-rw-r--r--lib/Reply/Plugin/Hints.pm15
-rw-r--r--lib/Reply/Plugin/Interrupt.pm13
-rw-r--r--lib/Reply/Plugin/LexicalPersistence.pm14
-rw-r--r--lib/Reply/Plugin/LoadClass.pm16
-rw-r--r--lib/Reply/Plugin/Nopaste.pm22
-rw-r--r--lib/Reply/Plugin/Packages.pm16
-rw-r--r--lib/Reply/Plugin/ReadLine.pm23
-rw-r--r--lib/Reply/Plugin/ResultCache.pm17
16 files changed, 467 insertions, 2 deletions
diff --git a/bin/reply b/bin/reply
index 6703852..3de86de 100644
--- a/bin/reply
+++ b/bin/reply
@@ -2,12 +2,28 @@
use strict;
use warnings;
# PODNAME: reply
+# ABSTRACT: read, eval, print, loop, yay!
use File::HomeDir;
use File::Spec;
use Reply;
+=head1 SYNOPSIS
+
+ reply
+
+=head1 DESCRIPTION
+
+This script runs the L<Reply> shell. It looks for a configuration file in
+C<.replyrc> in your home directory, and will generate a basic configuration for
+you if that file does not exist.
+
+See the L<Reply> documentation for more information about using and configuring
+this program.
+
+=cut
+
my $cfg = File::Spec->catfile(File::HomeDir->my_home, ".replyrc");
my %args = (config => $cfg);
diff --git a/lib/Reply.pm b/lib/Reply.pm
index d32ff05..53808bc 100644
--- a/lib/Reply.pm
+++ b/lib/Reply.pm
@@ -8,6 +8,71 @@ use Module::Runtime qw(compose_module_name use_package_optimistically);
use Scalar::Util qw(blessed);
use Try::Tiny;
+=head1 SYNOPSIS
+
+ use Reply;
+
+ Reply->new(config => "$ENV{HOME}/.replyrc")->run;
+
+=head1 DESCRIPTION
+
+Reply is a lightweight, extensible REPL for Perl. It is plugin-based (see
+L<Reply::Plugin>), and through plugins supports many advanced features such as
+coloring and pretty printing, readline support, and pluggable commands.
+
+=head1 CONFIGURATION
+
+Configuration uses an INI-style format similar to the configuration format of
+L<Dist::Zilla>. Section names are used as the names of plugins, and any options
+within a section are passed as arguments to that plugin. Plugins are loaded in
+order as they are listed in the configuration file, which can affect the
+results in some cases where multiple plugins are hooking into a single callback
+(see L<Reply::Plugin> for more information).
+
+In addition to plugin configuration, there are some additional options
+recognized. These must be specified at the top of the file, before any section
+headers.
+
+=over 4
+
+=item script_file
+
+This contains a filename whose contents will be evaluated as perl code once the
+configuration is done being loaded.
+
+=item script_lineI<n>
+
+Any options that start with C<script_line> will be sorted by their key and then
+each value will be evaluated individually once the configuration is done being
+loaded.
+
+NOTE: this is currently a hack due to the fact that L<Config::INI> doesn't
+support multiple keys with the same name in a section. This may be fixed in the
+future to just allow specifying C<script_line> multiple times.
+
+=back
+
+=cut
+
+=method new(%opts)
+
+Creates a new Reply instance. Valid options are:
+
+=over 4
+
+=item config
+
+Name of a configuration file to load. This should contain INI-style
+configuration for plugins as described above.
+
+=item plugins
+
+An arrayref of additional plugins to load.
+
+=back
+
+=cut
+
sub new {
my $class = shift;
my %opts = @_;
@@ -29,6 +94,14 @@ sub new {
return $self;
}
+=method load_plugin($plugin, $opts)
+
+Loads the specified plugin. C<$plugin> corresponds to the class
+C<Reply::Plugin::$plugin>, which will be loaded and instantiated. If C<$opts>
+is given, it should be a hashref of options to pass to the plugin constructor.
+
+=cut
+
sub load_plugin {
my $self = shift;
my ($plugin, $opts) = @_;
@@ -44,6 +117,13 @@ sub load_plugin {
push @{ $self->{plugins} }, $plugin;
}
+=method run
+
+Runs the repl. Will continue looping until the C<read_line> callback returns
+undef.
+
+=cut
+
sub run {
my $self = shift;
@@ -176,4 +256,46 @@ sub _chained_plugin {
return @args;
}
+=head1 BUGS
+
+No known bugs.
+
+Please report any bugs through RT: email
+C<bug-reply at rt.cpan.org>, or browse to
+L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Reply>.
+
+=head1 SEE ALSO
+
+L<Devel::REPL>
+
+=head1 SUPPORT
+
+You can find this documentation for this module with the perldoc command.
+
+ perldoc Reply
+
+You can also look for information at:
+
+=over 4
+
+=item * AnnoCPAN: Annotated CPAN documentation
+
+L<http://annocpan.org/dist/Reply>
+
+=item * CPAN Ratings
+
+L<http://cpanratings.perl.org/d/Reply>
+
+=item * RT: CPAN's request tracker
+
+L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Reply>
+
+=item * Search CPAN
+
+L<http://search.cpan.org/dist/Reply>
+
+=back
+
+=cut
+
1;
diff --git a/lib/Reply/Plugin.pm b/lib/Reply/Plugin.pm
index 0858758..ec16ddf 100644
--- a/lib/Reply/Plugin.pm
+++ b/lib/Reply/Plugin.pm
@@ -1,6 +1,123 @@
package Reply::Plugin;
use strict;
use warnings;
+# ABSTRACT: base class for Reply plugins
+
+=head1 SYNOPSIS
+
+ package Reply::Plugin::Foo;
+ use strict;
+ use warnings;
+
+ use base 'Reply::Plugin';
+
+ # ...
+
+=head1 DESCRIPTION
+
+A L<Reply> plugin is an object which adds some functionality to a Reply
+instance by implementing some specific methods which the Reply object will call
+at various points during execution. Plugins may implement as many callback
+methods as necessary to implement their functionality (although the more
+callbacks a given plugin implements, the more likely it is that the plugin may
+be more useful as multiple independent plugins).
+
+Callback methods have two potential calling conventions:
+
+=over 4
+
+=item wrapped
+
+Wrapped plugins receive a coderef as their first argument (before any arguments
+to the callback itself), and that coderef can be used to call the next callback
+in the list (if more than one plugin implements a given callback). In
+particular, this allows calling the next plugin multiple times, or not at all
+if necessary. Wrapped plugins should always call their coderef in list context.
+All plugins listed below are wrapped plugins unless indicated otherwise.
+
+=item chained
+
+Chained plugins receive a list of arguments, and return a new list of arguments
+which will be passed to the next plugin in the chain. This allows each plugin a
+chance to modify a value before it's actually used by the repl.
+
+=back
+
+=head2 CALLBACKS
+
+=over 4
+
+=item prompt
+
+Called to determine the prompt to use when reading the next line. Takes no
+arguments, and returns a single string to use as the prompt. The default
+implementation returns C<< ">" >>
+
+=item read_line
+
+Called to actually read a line from the user. Takes no arguments, and returns a
+single string. The default implementation uses the C<< <> >> operator to read a
+single line from the user.
+
+=item command_C<$name> (chained)
+
+If the line read from the user is of the form "#foo args...", then plugins will
+be searched for a callback method named C<command_foo>. This callback takes a
+single string containing the provided arguments, and returns a new line to
+evaluate instead, if any.
+
+=item mangle_line (chained)
+
+Modifies the line read from the user before it's evaluated. Takes the line as a
+string and returns the modified line.
+
+=item compile
+
+Compiles the string of Perl code into a coderef. Takes the line of code as a
+string and a hash of extra parameters, and returns the coderef to be executed.
+The default implementation uses L<Eval::Closure> to compile the given string.
+The extra parameters are passed directly to the C<eval_closure> call.
+
+=item execute
+
+Executes the coderef which has just been compiled. Takes the coderef and a list
+of parameters to pass to it, and returns the list of results returned by
+calling the coderef. The default implementation just calls the coderef
+directly.
+
+=item mangle_error (chained)
+
+If the C<compile> or C<execute> callbacks throw an exception, this callback
+will be called to modify the exception before it is passed to C<print_error>.
+It receives the exception and returns the modified exception.
+
+=item print_error
+
+If the C<compile> or C<execute> callbacks throw an exception, this callback
+will be called to display it to the user. It receives the exception and returns
+nothing. The default implementation just uses C<print> to print it to the
+screen.
+
+=item mangle_result (chained)
+
+This callback is used to modify the result of evaluating the line of code
+before it is displayed. It receives the list of results and returns a modified
+list of results.
+
+=item print_result
+
+This callback displays to the user the results of evaluating the given line of
+code. It receives the list of results, and returns nothing. The default
+implementation just uses C<print> to print them to the screen.
+
+=item loop (chained)
+
+This callback is called at the end of each evaluation. It receives no
+parameters and returns nothing.
+
+=back
+
+=cut
sub new { bless {}, shift }
diff --git a/lib/Reply/Plugin/Colors.pm b/lib/Reply/Plugin/Colors.pm
index 8b68119..839654d 100644
--- a/lib/Reply/Plugin/Colors.pm
+++ b/lib/Reply/Plugin/Colors.pm
@@ -1,11 +1,31 @@
package Reply::Plugin::Colors;
use strict;
use warnings;
+# ABSTRACT: colorize output
use base 'Reply::Plugin';
use Term::ANSIColor;
+=head1 SYNOPSIS
+
+ ; .replyrc
+ [Colors]
+ error = bright red
+ warning = bright yellow
+ result = bright green
+
+=head1 DESCRIPTION
+
+This plugin adds coloring to the results when they are printed to the screen.
+By default, errors are C<red>, warnings are C<yellow>, and normal results are
+C<green>, although this can be overridden through configuration as shown in the
+synopsis. L<Term::ANSIColor> is used to generate the colors, so any value that
+is accepted by that module is a valid value for the C<error>, C<warning>, and
+C<result> options.
+
+=cut
+
sub new {
my $class = shift;
my %opts = @_;
diff --git a/lib/Reply/Plugin/DataDump.pm b/lib/Reply/Plugin/DataDump.pm
index e80deab..64d756e 100644
--- a/lib/Reply/Plugin/DataDump.pm
+++ b/lib/Reply/Plugin/DataDump.pm
@@ -1,11 +1,23 @@
package Reply::Plugin::DataDump;
use strict;
use warnings;
+# ABSTRACT: format results using Data::Dump
use base 'Reply::Plugin';
use Data::Dump 'pp';
+=head1 SYNOPSIS
+
+ ; .replyrc
+ [DataDumper]
+
+=head1 DESCRIPTION
+
+This plugin uses L<Data::Dump> to format results.
+
+=cut
+
sub mangle_result {
my $self = shift;
my (@result) = @_;
diff --git a/lib/Reply/Plugin/DataDumper.pm b/lib/Reply/Plugin/DataDumper.pm
index 676344a..7491c60 100644
--- a/lib/Reply/Plugin/DataDumper.pm
+++ b/lib/Reply/Plugin/DataDumper.pm
@@ -1,11 +1,23 @@
package Reply::Plugin::DataDumper;
use strict;
use warnings;
+# ABSTRACT: format results using Data::Dumper
use base 'Reply::Plugin';
use Data::Dumper;
+=head1 SYNOPSIS
+
+ ; .replyrc
+ [DataDumper]
+
+=head1 DESCRIPTION
+
+This plugin uses L<Data::Dumper> to format results.
+
+=cut
+
sub mangle_result {
my $self = shift;
my (@result) = @_;
diff --git a/lib/Reply/Plugin/Editor.pm b/lib/Reply/Plugin/Editor.pm
index fe5c23e..e7ff91d 100644
--- a/lib/Reply/Plugin/Editor.pm
+++ b/lib/Reply/Plugin/Editor.pm
@@ -1,6 +1,7 @@
package Reply::Plugin::Editor;
use strict;
use warnings;
+# ABSTRACT: command to edit the current line in a text editor
use base 'Reply::Plugin';
@@ -8,6 +9,25 @@ use File::HomeDir;
use File::Spec;
use Proc::InvokeEditor;
+=head1 SYNOPSIS
+
+ ; .replyrc
+ [Editor]
+ editor = emacs
+
+=head1 DESCRIPTION
+
+This plugin provides the C<#e> command. It will launch your editor, and allow
+you to edit bits of code in your editor, which will then be evaluated all at
+once. The text you entered will be saved, and restored the next time you enter
+the command. Alternatively, you can pass a filename to the C<#e> command, and
+the contents of that file will be preloaded instead.
+
+The C<editor> option can be specified to provide a different editor to use,
+otherwise it will use the value of C<$ENV{VISUAL}> or C<$ENV{EDITOR}>.
+
+=cut
+
sub new {
my $class = shift;
my %opts = @_;
diff --git a/lib/Reply/Plugin/FancyPrompt.pm b/lib/Reply/Plugin/FancyPrompt.pm
index d998763..d0afc38 100644
--- a/lib/Reply/Plugin/FancyPrompt.pm
+++ b/lib/Reply/Plugin/FancyPrompt.pm
@@ -1,9 +1,23 @@
package Reply::Plugin::FancyPrompt;
use strict;
use warnings;
+# ABSTRACT: provides a more informative prompt
use base 'Reply::Plugin';
+=head1 SYNOPSIS
+
+ ; .replyrc
+ [FancyPrompt]
+
+=head1 DESCRIPTION
+
+This plugin enhances the default Reply prompt. Currently, the only difference
+is that it includes a counter of the number of lines evaluated so far in the
+current session.
+
+=cut
+
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
diff --git a/lib/Reply/Plugin/Hints.pm b/lib/Reply/Plugin/Hints.pm
index ac31ceb..d36d14a 100644
--- a/lib/Reply/Plugin/Hints.pm
+++ b/lib/Reply/Plugin/Hints.pm
@@ -11,9 +11,24 @@ BEGIN {
use strict;
use warnings;
+# ABSTRACT: persists lexical hints across input lines
use base 'Reply::Plugin';
+=head1 SYNOPSIS
+
+ ; .replyrc
+ [Hints]
+
+=head1 DESCRIPTION
+
+This plugin persists the values of various compile time lexical hints between
+evaluated lines. This means, for instance, that entering a line like C<use
+strict> at the Reply prompt will cause C<strict> to be enabled for all future
+lines (at least until C<no strict> is given).
+
+=cut
+
sub new {
my $class = shift;
diff --git a/lib/Reply/Plugin/Interrupt.pm b/lib/Reply/Plugin/Interrupt.pm
index a5c2b37..1aab2b8 100644
--- a/lib/Reply/Plugin/Interrupt.pm
+++ b/lib/Reply/Plugin/Interrupt.pm
@@ -1,9 +1,22 @@
package Reply::Plugin::Interrupt;
use strict;
use warnings;
+# ABSTRACT: allows using Ctrl+C to interrupt long-running lines
use base 'Reply::Plugin';
+=head1 SYNOPSIS
+
+ ; .replyrc
+ [Interrupt]
+
+=head1 DESCRIPTION
+
+This plugin allows you to use Ctrl+C to interrupt long running commands without
+exiting the Reply shell entirely.
+
+=cut
+
sub compile {
my $self = shift;
my ($next, @args) = @_;
diff --git a/lib/Reply/Plugin/LexicalPersistence.pm b/lib/Reply/Plugin/LexicalPersistence.pm
index deb8d94..3b1f3f5 100644
--- a/lib/Reply/Plugin/LexicalPersistence.pm
+++ b/lib/Reply/Plugin/LexicalPersistence.pm
@@ -1,11 +1,25 @@
package Reply::Plugin::LexicalPersistence;
use strict;
use warnings;
+# ABSTRACT: persists lexical variables between lines
use base 'Reply::Plugin';
use Lexical::Persistence;
+=head1 SYNOPSIS
+
+ ; .replyrc
+ [LexicalPersistence]
+
+=head1 DESCRIPTION
+
+This plugin persists the values of lexical variables between input lines. For
+instance, with this plugin you can enter C<my $x = 2> into the Reply shell, and
+then use C<$x> as expected in subsequent lines.
+
+=cut
+
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
diff --git a/lib/Reply/Plugin/LoadClass.pm b/lib/Reply/Plugin/LoadClass.pm
index 8bba634..a225cdd 100644
--- a/lib/Reply/Plugin/LoadClass.pm
+++ b/lib/Reply/Plugin/LoadClass.pm
@@ -1,12 +1,28 @@
package Reply::Plugin::LoadClass;
use strict;
use warnings;
+# ABSTRACT: attempts to load classes implicitly if possible
use base 'Reply::Plugin';
use Module::Runtime 'use_package_optimistically';
use Try::Tiny;
+=head1 SYNOPSIS
+
+ ; .replyrc
+ [LoadClass]
+
+=head1 DESCRIPTION
+
+If executing a line of code fails due to a method not being defined on a
+package, this plugin will load the corresponding module and then try executing
+the line again. This simplifies common cases like running C<< DateTime->now >>
+at the prompt before loading L<DateTime> - this plugin will cause DateTime to
+be loaded implicitly.
+
+=cut
+
sub execute {
my $self = shift;
my ($next, @args) = @_;
diff --git a/lib/Reply/Plugin/Nopaste.pm b/lib/Reply/Plugin/Nopaste.pm
index 1f64f85..085e478 100644
--- a/lib/Reply/Plugin/Nopaste.pm
+++ b/lib/Reply/Plugin/Nopaste.pm
@@ -1,13 +1,31 @@
package Reply::Plugin::Nopaste;
use strict;
use warnings;
+# ABSTRACT: command to nopaste a transcript of the current session
use base 'Reply::Plugin';
use App::Nopaste;
-# XXX note that this has to be loaded early, in order to catch all of the
-# appropriate manipulations that plugins do ([DataDump], etc)
+=head1 SYNOPSIS
+
+ ; .replyrc
+ [Nopaste]
+ service = Gist
+
+=head1 DESCRIPTION
+
+This plugin provides a C<#nopaste> command, which will use L<App::Nopaste> to
+nopaste a transcript of the current Reply session. The C<service> option can be
+used to choose an alternate service to use, rather than using the one that
+App::Nopaste chooses on its own. If arguments are passed to the C<#nopaste>
+command, they will be used as the title of the paste.
+
+Note that this plugin should be loaded early in your configuration file, in
+order to ensure that it sees all modifications to the result (due to plugins
+like [DataDump], etc).
+
+=cut
sub new {
my $class = shift;
diff --git a/lib/Reply/Plugin/Packages.pm b/lib/Reply/Plugin/Packages.pm
index fd48737..eb69f96 100644
--- a/lib/Reply/Plugin/Packages.pm
+++ b/lib/Reply/Plugin/Packages.pm
@@ -1,9 +1,25 @@
package Reply::Plugin::Packages;
use strict;
use warnings;
+# ABSTRACT: persist the current package between lines
use base 'Reply::Plugin';
+=head1 SYNOPSIS
+
+ ; .replyrc
+ [Packages]
+ default_package = My::Scratchpad
+
+=head1 DESCRIPTION
+
+This plugin persists the state of the current package between lines. This
+allows lines such as C<package Foo;> in the Reply shell to do what you'd
+expect. The C<default_package> configuration option can also be used to set the
+initial package to use when Reply starts up.
+
+=cut
+
sub new {
my $class = shift;
my %opts = @_;
diff --git a/lib/Reply/Plugin/ReadLine.pm b/lib/Reply/Plugin/ReadLine.pm
index 39126d1..6fcb0ad 100644
--- a/lib/Reply/Plugin/ReadLine.pm
+++ b/lib/Reply/Plugin/ReadLine.pm
@@ -1,6 +1,7 @@
package Reply::Plugin::ReadLine;
use strict;
use warnings;
+# ABSTRACT: use Term::ReadLine for user input
use base 'Reply::Plugin';
@@ -8,6 +9,28 @@ use File::HomeDir;
use File::Spec;
use Term::ReadLine;
+=head1 SYNOPSIS
+
+ ; .replyrc
+ [ReadLine]
+ history_file = '.hist'
+ history_length = 100
+
+=head1 DESCRIPTION
+
+This plugin uses L<Term::ReadLine> to read lines from the user. This enables
+useful features such as line editing and command history. The history will be
+persisted between runs, by default in C<~/.reply_history>, although this is
+changeable with the C<history_file> option. To limit the number of lines
+written to this file, you can use the C<history_length> option. Setting a
+C<history_length> of C<0> will disable writing history to a file entirely.
+
+NOTE: you probably want to install a reasonable L<Term::ReadLine> backend in
+order for this plugin to be very useful. L<Term::ReadLine::Gnu> is highly
+recommended if possible.
+
+=cut
+
sub new {
my $class = shift;
my %opts = @_;
diff --git a/lib/Reply/Plugin/ResultCache.pm b/lib/Reply/Plugin/ResultCache.pm
index fc260f5..a973d05 100644
--- a/lib/Reply/Plugin/ResultCache.pm
+++ b/lib/Reply/Plugin/ResultCache.pm
@@ -1,9 +1,26 @@
package Reply::Plugin::ResultCache;
use strict;
use warnings;
+# ABSTRACT: retain previous results to be able to refer to them later
use base 'Reply::Plugin';
+=head1 SYNOPSIS
+
+ ; .replyrc
+ [ResultCache]
+ variable = r
+
+=head1 DESCRIPTION
+
+This plugin caches the results of successful evaluations, and provides them in
+a lexical array (by default C<@res>, although this can be changed via the
+C<variable> option). This means that you can, for instance, access the value
+returned by the previous line with C<$res[-1]>. It also modifies the output to
+include an indication of where the value is stored, for later reference.
+
+=cut
+
sub new {
my $class = shift;
my %opts = @_;