Skip to content

Commit

Permalink
Build results of 326aa1e (on master)
Browse files Browse the repository at this point in the history
  • Loading branch information
kentfredric committed Apr 27, 2016
1 parent a2f2f15 commit 16ad5e7
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Changes
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Release history for Dist-Zilla-Plugin-Beam-Connector

0.001000 2016-04-27T05:30:30Z 1c312f2
0.001000 2016-04-27T06:40:03Z 326aa1e
- First version.

114 changes: 114 additions & 0 deletions lib/Dist/Zilla/Plugin/Beam/Connector.pm
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,120 @@ that C<emitter>
For a C<listener>, the C<connector> property identifies the name of a C<method> that is expected to receive the event.
=head1 WRITING EVENT EMITTERS
Adding support for hookable events in new and existing C<Dist::Zilla> plugins is relatively straight-forward,
and uses L<< C<Beam::Emitter>|Beam::Emitter >>
# Somewhere after `use Moose`
with "Beam::Emitter";
And your class is now ready to broadcast events, and plugins are now able to hook events. Even though they don't
exist yet.
But that's not very useful in itself. You need to find good places in your code to write events, and construct
little bundles of state, "messages" to pass around, and perhaps, allow modifying.
=head2 Designing an Event
You want to start off designing an event class that communicates the I<absolute minimum> required to be useful.
Carrying too much state, or too much indirect state is the enemy.
For instance, it would generally be unwise to design an Event that you passed to something which carried a C<$zilla>
instance with it.
You want to make it as obscure as possible who is even sending the event, as the contents of the event should be usable
in total isolation, because you have no idea where your events are going to get sent ( because that is outside the
scope of your plugin ), and receivers have no solid expectations of where events are going to come from ( because that
is dictated by the connector ).
=head2 Implementing an Event
Events themselves are quite straight forward: They're just objects, objects extending
L<< C<Beam::Event>|Beam::Event >>.
It is presently recommended you define these events inline somewhere, either in the plugin that emits them,
or in some shared container.
It is also recommended to I<NOT> index said Event packages at present.
This is an example event definition: It will communicate a file name it intends to prepend lines to
and pass a mutable, empty array for the event handler to inject lines into.
package # hide from PAUSE
Dist::Zilla::Plugin::Prepender::AppenderEvent;
use Moose; # or Moose, both work
extends "Beam::Event"
has 'filename' => (
is => 'ro',
isa => Str,
required => 1,
);
has 'lines' => (
is => 'rw',
isa => ArrayRef[Str],
lazy => 1,
default => sub { [] },
);
__PACKAGE__->meta->make_immutable;
See L<< Using Custom Events in Beam::Emitter|Beam::Emitter/Using Custom Events >> for details.
=head2 Emitting and Handling an Event
Once you have an Event class designed, gluing it into your code is also quite simple:
# somewhere deep in your plugin
my $event = $self->emit(
'before_append', # the "name" of the event, this corresponds to the "connector"
# property in Beam::Connector
class => 'Dist::Zilla::Plugin::Prepender::AppenderEvent', # The class to construct an instance of
filename => 'lib/Foo.pm', # attribute property of the Event object.
);
An instance of C<class> is created with the defined name, and is passed in-order to all the objects who subscribed to the
C<before_append> event, and then returned once they're done.
And then you can extract any of the state in the passed object and use it to do your work.
=head3 Using events to replace default behavior
You can optionally use the event system as a way to toggle between default and customized behavior.
For instance:
my $event = $self->emit("before_append" ... );
if ( !$event->is_default_stopped ) {
unshift, @{$event->lines}, 'use strict;','use warnings;';
}
With this configuration, all the events registered will run, and the later block
can be turned off by any events in the stack.
=head3 "Stopped" events
Event receivers can also indicate to "stop" an event in somehow.
"Stopping" an event skips all subsequent registered listeners,
and marks the event as "stopped", L<< in addition to being "default_stopped"|Beam::Event/stop >>
my $event = $self->emit("before_append" ... );
if ( !$event->is_default_stopped ) {
# Won't fire after either a ->stop or a ->stop_default
unshift, @{$event->lines}, 'use strict;','use warnings;';
}
if ( $event->is_stopped ) {
# Won't fire with ->stop_default, but will fire with ->stop
return;
}
# do appending here
=head1 AUTHOR
Kent Fredric <kentnl@cpan.org>
Expand Down
2 changes: 1 addition & 1 deletion maint/perlcritic.rc.gen.pl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
my $bundle = create_bundle('Example::Author::KENTNL');
$bundle->configure;

my @stopwords = (qw());
my @stopwords = (qw( hookable prepend ));
for my $wordlist (@stopwords) {
$bundle->add_or_append_policy_field( 'Documentation::PodSpelling' => ( 'stop_words' => $wordlist ) );
}
Expand Down
1 change: 1 addition & 0 deletions misc/perlcritic.deps
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Perl::Critic::Policy::Documentation::PodSpelling~0
Perl::Critic::Policy::Lax::RequireExplicitPackage::ExceptForPragmata~0
Perl::Critic::Policy::Variables::ProhibitUnusedVarsStricter~0
Perl::Critic::ProfileCompiler::Bundle::Bangs~0
Expand Down
1 change: 1 addition & 0 deletions perlcritic.rc
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ allow_includes = 1

[Documentation::PodSpelling]
spell_command = aspell list --lang en_US
stop_words = hookable prepend

[Documentation::ProhibitAdjacentLinks]

Expand Down

0 comments on commit 16ad5e7

Please sign in to comment.