Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add a quick round of documentation, and edit some code and examples f…

…or brevity.
  • Loading branch information...
commit 30dfe8c372d57a83710e54f8c147e06aaf8364c2 1 parent d75f256
Rocco Caputo authored
22 MANIFEST
View
@@ -0,0 +1,22 @@
+CHANGES
+MANIFEST
+META.yml
+Makefile.PL
+README
+lib/Reflex.pm
+lib/Reflex/Handle.pm
+lib/Reflex/Object.pm
+lib/Reflex/PID.pm
+lib/Reflex/POE/Event.pm
+lib/Reflex/POE/Postback.pm
+lib/Reflex/POE/Session.pm
+lib/Reflex/POE/Wheel.pm
+lib/Reflex/POE/Wheel/Run.pm
+lib/Reflex/Role/Object.pm
+lib/Reflex/Role/UdpPeer.pm
+lib/Reflex/Signal.pm
+lib/Reflex/Timer.pm
+lib/Reflex/Trait/Emitter.pm
+lib/Reflex/Trait/Observer.pm
+lib/Reflex/UdpPeer.pm
+t/00_info.t
33 Makefile.PL
View
@@ -0,0 +1,33 @@
+use ExtUtils::MakeMaker;
+
+# Touch auto-generated files so we don't see warnings.
+open(CHANGES, ">>CHANGES") and close CHANGES;
+open(README, ">>README") and close README;
+
+WriteMakefile(
+ NAME => 'Reflex',
+ AUTHOR => 'Rocco Caputo <rcaputo@cpan.org>',
+ ABSTRACT => 'Reactive classes for flexible programs.',
+ LICENSE => 'perl',
+ VERSION_FROM => 'lib/Reflex.pm',
+ PREREQ_PM => {
+ 'Scalar::Util' => 1.21,
+ 'POE' => 1.268,
+ 'Test::More' => 0.94,
+ 'Moose' => 0.92,
+ },
+ META_ADD => {
+ resources => {
+ license => 'http://dev.perl.org/licenses/',
+ repository => 'http://github.com/rcaputo/poe-stage/',
+ },
+ },
+ dist => {
+ COMPRESS => 'gzip -9f',
+ SUFFIX => 'gz',
+ PREOP => (
+ 'git-log.pl | tee ./$(DISTNAME)-$(VERSION)/CHANGES > ./CHANGES;' .
+ 'LANG=C perldoc lib/Reflex.pm > README'
+ ),
+ },
+);
29 eg-05-composition.pl
View
@@ -14,25 +14,20 @@
extends 'Reflex::Object';
use Reflex::UdpPeer;
- has peer => (
- isa => 'Reflex::UdpPeer|Undef',
- is => 'rw',
+ has port => (
+ isa => 'Int',
+ is => 'ro',
);
- sub BUILD {
- my ($self, $args) = @_;
- $self->peer(
- Reflex::UdpPeer->new(
- port => $args->{port},
- observers => [
- {
- observer => $self,
- role => 'peer',
- }
- ]
- )
- );
- }
+ has peer => (
+ isa => 'Reflex::UdpPeer|Undef',
+ is => 'rw',
+ traits => ['Reflex::Trait::Observer'],
+ setup => sub {
+ my $self = shift;
+ Reflex::UdpPeer->new(port => $self->port());
+ },
+ );
sub on_peer_datagram {
my ($self, $args) = @_;
63 eg-15-handle.pl
View
@@ -0,0 +1,63 @@
+#!/usr/bin/env perl
+
+use lib qw(lib);
+
+{
+ package UdpPeer;
+
+ use Moose;
+ extends 'Reflex::Object';
+ use Reflex::Handle;
+
+ has port => (
+ isa => 'Int',
+ is => 'ro',
+ );
+
+ has handle => (
+ isa => 'Reflex::Handle|Undef',
+ is => 'rw',
+ traits => ['Reflex::Trait::Observer'],
+ role => 'remote',
+ );
+
+ after 'BUILD' => sub {
+ my $self = shift;
+
+ $self->handle(
+ Reflex::Handle->new(
+ handle => IO::Socket::INET->new(
+ Proto => 'udp',
+ LocalPort => $self->port(),
+ ),
+ rd => 1,
+ )
+ );
+ undef;
+ };
+
+ sub on_remote_read {
+ my ($self, $args) = @_;
+
+ my $remote_address = recv(
+ $args->{handle},
+ my $datagram = "",
+ 16384,
+ 0
+ );
+
+ if ($datagram =~ /^\s*quit\s*$/i) {
+ $self->handle(undef);
+ return;
+ }
+
+ return if send(
+ $args->{handle},
+ $datagram,
+ 0,
+ $remote_address,
+ ) == length($datagram);
+ }
+}
+
+exit UdpPeer->new( port => 12345 )->run_all();
152 lib/Reflex.pm
View
@@ -8,26 +8,26 @@ use Carp qw(croak);
our $VERSION = '0.001';
sub import {
- my $class = shift;
- my $caller_package = caller();
-
- # Use the packages in the caller's package.
- # TODO - I think lexical magic isn't supported.
-
- eval join(
- "; ",
- "package $caller_package",
- map { "use $class\::$_" }
- @_
- );
-
-
- # Rewrite the error so that it comes from the caller.
- if ($@) {
- my $msg = $@;
- $msg =~ s/(\(\@INC contains.*?\)) at .*/$1/s;
- croak $msg;
- }
+ my $class = shift;
+ my $caller_package = caller();
+
+ # Use the packages in the caller's package.
+ # TODO - I think lexical magic isn't supported.
+
+ eval join(
+ "; ",
+ "package $caller_package",
+ map { "use $class\::$_" }
+ @_
+ );
+
+
+ # Rewrite the error so that it comes from the caller.
+ if ($@) {
+ my $msg = $@;
+ $msg =~ s/(\(\@INC contains.*?\)) at .*/$1/s;
+ croak $msg;
+ }
}
1;
@@ -40,64 +40,108 @@ Reflex - Reactive classes for flexible programs.
=head1 SYNOPSIS
- {
- package App;
- use Moose;
- extends 'Reflex::Object';
- use Reflex::Timer;
+ {
+ package App;
+ use Moose;
+ extends 'Reflex::Object';
+ use Reflex::Timer;
- has ticker => (
- isa => 'Reflex::Timer',
- is => 'rw',
- setup => { interval => 1, auto_repeat => 1 },
- traits => [ 'Reflex::Trait::Observer' ],
- );
+ has ticker => (
+ isa => 'Reflex::Timer',
+ is => 'rw',
+ setup => { interval => 1, auto_repeat => 1 },
+ traits => [ 'Reflex::Trait::Observer' ],
+ );
- sub on_ticker_tick {
- print "tick at ", scalar(localtime), "...\n";
- }
- }
+ sub on_ticker_tick {
+ print "tick at ", scalar(localtime), "...\n";
+ }
+ }
- exit App->new()->run_all();
+ exit App->new()->run_all();
=head1 DESCRIPTION
Reflex is a suite of classes to help programmers write reactive
-programs. More to come
+programs. The project has some goals:
+
+=over 2
+
+=item * Be concise.
+
+=item * Be convenient.
+
+=item * Be portable.
+
+=item * Be fast.
+
+=item * Don't get in the way.
+
+=item * Release early, and release often.
+
+=back
+
+Sorry for the lack of documentation. It conflicted with releasing
+early. Contributions are very much welcome. Give the project a
+reason to release often.
+
+TODO - Complete the documentation.
=head1 GETTING HELP
-POE's mailing list.
-Channel #poe on irc.perl.org.
+See irc.perl.org #moose for help with Moose.
+
+See irc.perl.org #poe for help with POE and Reflex.
+
+Support is officially available from POE's mailing list as well. Send
+a blank message to
+L<poe-subscribe@perl.org|mailto:poe-subscribe@perl.org>
+to join.
=head1 ACKNOWLEDGEMENTS
-irc.perl.org channel #moose and #poe. The former for assisting in
-learning their fine libraries, sometimes against everyone's better
-judgement. The latter for putting up with lengthy and sometimes
-irrelevant design discussion for oh so long.
+irc.perl.org channel
+L<#moose|irc://irc.perl.org/moose>
+and
+L<#poe|irc://irc.perl.org/moose>.
+The former for assisting in learning their fine libraries, sometimes
+against everyone's better judgement. The latter for putting up with
+lengthy and sometimes irrelevant design discussion for oh so long.
=head1 SEE ALSO
-Moose
-POE
-Ohlo
-Reflex namespace on CPAN.
-Links to tutorials & reviews.
-Home page for Reflex.
+L<Moose>, L<POE>, the Reflex namespace on CPAN.
+
+TODO - Set up ohlo.
+
+TODO - Set up CIA.
+
+TODO - Set up home page.
=head1 BUGS
-TODO - Link to Reflex's RT queue. Explain how to send e-mail, too.
+We appreciate your feedback, bug reports, feature requests, patches
+and kudos. You may enter them into our request tracker by following
+the instructions at
+L<https://rt.cpan.org/Dist/Display.html?&Queue=Reflex>.
+
+We also accept e-mail at
+L<bug-Reflex@rt.cpan.org|mailto:bug-Reflex@rt.cpan.org>.
=head1 AUTHORS
-Rocco Caputo
-Point out that it's a FOSS project, and anyone may contribute.
+Rocco Caputo, and a (hopefully) growing cadre of contributors---
+perhaps including you. Reflex is open source, and we welcome
+involvement.
=head2 OTHER CONTRIBUTORS
-List here, when there are some.
+Nobody yet. As of this writing, Reflex has not yet been released.
+
+=head1 TODO
+
+Please browse the source for the TODO marker. Some are visible in the
+documentation, and others are sprinlked around in the code's comments.
=head1 COPYRIGHT AND LICCENSE
@@ -106,6 +150,6 @@ Copyright 2009 by Rocco Caputo.
Reflex is free software. You may redistribute and/or modify it under
the same terms as Perl itself.
-TODO - Recommended best practice for licenses.
+TODO - Use the latest recommended best practice for licenses.
=cut
80 lib/Reflex/Handle.pm
View
@@ -82,3 +82,83 @@ no Moose;
__PACKAGE__->meta()->make_immutable();
1;
+
+__END__
+
+=head1 NAME
+
+Reflex::Handle - Base class for reactive filehandle objects.
+
+=head1 SYNOPSIS
+
+# Not a complete program. See Reflex::Role::UdpPeer source, or
+# eg-15-handle.pl in the examples.
+
+ has handle => (
+ isa => 'Reflex::Handle|Undef',
+ is => 'rw',
+ traits => ['Reflex::Trait::Observer'],
+ role => 'remote',
+ );
+
+ $self->handle(
+ Reflex::Handle->new(
+ handle => IO::Socket::INET->new(
+ Proto => 'udp',
+ LocalPort => $self->port(),
+ ),
+ rd => 1,
+ )
+ );
+
+ sub on_remote_read {
+ my ($self, $args) = @_;
+
+ my $remote_address = recv(
+ $args->{handle}, my $datagram = "", 16384, 0
+ );
+
+ send(
+ $args->{handle}, $datagram, 0, $remote_address
+ );
+ }
+
+=head1 DESCRIPTION
+
+B<This is early release code. Please contact us to discuss the API.>
+
+Reflex::Handle watches a filehandle and emits events when it has data
+to be read, is ready to be written upon, or has some exceptional
+condition to be addressed.
+
+TODO - Complete the documentation.
+
+=head1 GETTING HELP
+
+L<Reflex/GETTING HELP>
+
+=head1 ACKNOWLEDGEMENTS
+
+L<Reflex/ACKNOWLEDGEMENTS>
+
+=head1 SEE ALSO
+
+L<Reflex> and L<Reflex/SEE ALSO>
+
+=head1 BUGS
+
+L<Reflex/BUGS>
+
+=head1 CORE AUTHORS
+
+L<Reflex/CORE AUTHORS>
+
+=head1 OTHER CONTRIBUTORS
+
+L<Reflex/OTHER CONTRIBUTORS>
+
+=head1 COPYRIGHT AND LICENSE
+
+L<Reflex/COPYRIGHT AND LICENSE>
+
+=cut
55 lib/Reflex/Object.pm
View
@@ -10,3 +10,58 @@ no Moose;
__PACKAGE__->meta()->make_immutable();
1;
+
+__END__
+
+=head1 NAME
+
+Reflex::Object - Base class for reactive objects.
+
+=head1 SYNOPSIS
+
+ {
+ package Object;
+ use Moose;
+ extends 'Reflex::Object';
+ ...;
+ }
+
+=head1 DESCRIPTION
+
+Reflex::Object is the base class for all Reflex objects, including
+many of the event watchers.
+
+Please see L<Reflex::Role::Object> for actual documentation. The role
+implements Reflex::Object's internals.
+
+TODO - Complete the documeentation.
+
+=head1 GETTING HELP
+
+L<Reflex/GETTING HELP>
+
+=head1 ACKNOWLEDGEMENTS
+
+L<Reflex/ACKNOWLEDGEMENTS>
+
+=head1 SEE ALSO
+
+L<Reflex> and L<Reflex/SEE ALSO>
+
+=head1 BUGS
+
+L<Reflex/BUGS>
+
+=head1 CORE AUTHORS
+
+L<Reflex/CORE AUTHORS>
+
+=head1 OTHER CONTRIBUTORS
+
+L<Reflex/OTHER CONTRIBUTORS>
+
+=head1 COPYRIGHT AND LICENSE
+
+L<Reflex/COPYRIGHT AND LICENSE>
+
+=cut
75 lib/Reflex/PID.pm
View
@@ -33,3 +33,78 @@ no Moose;
__PACKAGE__->meta()->make_immutable();
1;
+
+__END__
+
+=head1 NAME
+
+Reflex::PID - Observe the exit of a subprocess, via handling SIGCHLD.
+
+=head1 SYNOPSIS
+
+# Not a complete program. Please see the source for
+# Reflex::POE::Wheel::Run for one example.
+
+ use Reflex::PID;
+
+ has sigchild_watcher => (
+ isa => 'Reflex::PID|Undef',
+ is => 'rw',
+ traits => ['Reflex::Trait::Observer'],
+ role => 'sigchld',
+ );
+
+ sub some_method {
+ my $self = shift;
+
+ my $pid = fork();
+ die $! unless defined $pid;
+ exec("some-program.pl") unless $pid;
+
+ # Parent here.
+ $self->sigchild_watcher(
+ Reflex::PID->new(pid => $pid)
+ );
+ }
+
+ sub on_sigchld_signal {
+ # Handle the event.
+ }
+
+=head1 DESCRIPTION
+
+Reflex::PID waits for a child process to exit, then announces the fact
+by emitting a "signal" event.
+
+TODO - Complete the documentation, including the parameters of the
+signal event.
+
+=head1 GETTING HELP
+
+L<Reflex/GETTING HELP>
+
+=head1 ACKNOWLEDGEMENTS
+
+L<Reflex/ACKNOWLEDGEMENTS>
+
+=head1 SEE ALSO
+
+L<Reflex> and L<Reflex/SEE ALSO>
+
+=head1 BUGS
+
+L<Reflex/BUGS>
+
+=head1 CORE AUTHORS
+
+L<Reflex/CORE AUTHORS>
+
+=head1 OTHER CONTRIBUTORS
+
+L<Reflex/OTHER CONTRIBUTORS>
+
+=head1 COPYRIGHT AND LICENSE
+
+L<Reflex/COPYRIGHT AND LICENSE>
+
+=cut
70 lib/Reflex/POE/Event.pm
View
@@ -47,3 +47,73 @@ sub deliver {
}
1;
+
+__END__
+
+=head1 NAME
+
+Reflex::POE::Event - Communicate with POE components expecting events.
+
+=head1 SYNOPSIS
+
+# Not a complete example. Please see eg-12-poco-event.pl in the
+# examples for a working one.
+
+ $self->run_within_session(
+ sub {
+ $self->component->request(
+ Reflex::POE::Event->new(
+ object => $self,
+ method => "on_component_result",
+ context => { cookie => 123 },
+ ),
+ );
+ }
+ );
+
+TODO - Needs a better example.
+
+=head1 DESCRIPTION
+
+Reflex::POE::Event creates an object that may be used as a POE event.
+When this event is posted back to Reflex, it will be routed to the
+proper Reflex::Object and method.
+
+Reflex will clean up its bookkeeping for this event when the object is
+destroyed. It's therefore important to maintain the object's blessing
+until it's definitely through being used.
+
+TODO - Is there a better, more reliable way to track the end of an
+event's use?
+
+TODO - Complete the documentation.
+
+=head1 GETTING HELP
+
+L<Reflex/GETTING HELP>
+
+=head1 ACKNOWLEDGEMENTS
+
+L<Reflex/ACKNOWLEDGEMENTS>
+
+=head1 SEE ALSO
+
+L<Reflex> and L<Reflex/SEE ALSO>
+
+=head1 BUGS
+
+L<Reflex/BUGS>
+
+=head1 CORE AUTHORS
+
+L<Reflex/CORE AUTHORS>
+
+=head1 OTHER CONTRIBUTORS
+
+L<Reflex/OTHER CONTRIBUTORS>
+
+=head1 COPYRIGHT AND LICENSE
+
+L<Reflex/COPYRIGHT AND LICENSE>
+
+=cut
57 lib/Reflex/POE/Postback.pm
View
@@ -52,3 +52,60 @@ sub DESTROY {
}
1;
+
+__END__
+
+=head1 NAME
+
+Reflex::POE::Postback - Communicate with POE components expecting postbacks.
+
+=head1 SYNOPSIS
+
+# Not a complete example. Please see eg-11-poco-postback.pl in the
+# examples for a working one.
+
+ $self->component->request(
+ Reflex::POE::Postback->new(
+ $self, "on_component_result", { cookie => 123 }
+ ),
+ );
+
+TODO - Needs a better example.
+
+=head1 DESCRIPTION
+
+Reflex::POE::Postback creates an object that's compatible with POE
+postbacks. They may be given to POE components that require them to
+work.
+
+TODO - Complete the documentation.
+
+=head1 GETTING HELP
+
+L<Reflex/GETTING HELP>
+
+=head1 ACKNOWLEDGEMENTS
+
+L<Reflex/ACKNOWLEDGEMENTS>
+
+=head1 SEE ALSO
+
+L<Reflex> and L<Reflex/SEE ALSO>
+
+=head1 BUGS
+
+L<Reflex/BUGS>
+
+=head1 CORE AUTHORS
+
+L<Reflex/CORE AUTHORS>
+
+=head1 OTHER CONTRIBUTORS
+
+L<Reflex/OTHER CONTRIBUTORS>
+
+=head1 COPYRIGHT AND LICENSE
+
+L<Reflex/COPYRIGHT AND LICENSE>
+
+=cut
85 lib/Reflex/POE/Session.pm
View
@@ -42,3 +42,88 @@ sub deliver {
}
1;
+
+__END__
+
+=head1 NAME
+
+Reflex::POE::Session - Observe events from a POE::Session object.
+
+=head1 SYNOPSIS
+
+# Not a complete example. Please see eg-13-irc-bot.pl in the examples
+# for a working one.
+
+
+ has poco_watcher => (
+ isa => 'Reflex::POE::Session',
+ is => 'rw',
+ traits => ['Reflex::Trait::Observer'],
+ role => 'poco',
+ );
+
+ sub BUILD {
+ my $self = shift;
+
+ $self->component(
+ POE::Component::IRC->spawn(
+ nick => "reflex_$$",
+ ircname => "Reflex Test Bot",
+ server => "10.0.0.25",
+ ) || die "Drat: $!"
+ );
+
+ $self->poco_watcher(
+ Reflex::POE::Session->new(
+ sid => $self->component()->session_id(),
+ )
+ );
+
+ $self->run_within_session(
+ sub {
+ $self->component()->yield(register => "all");
+ $self->component()->yield(connect => {});
+ }
+ )
+ }
+
+TODO - Either complete the example, or find a shorter one.
+
+=head1 DESCRIPTION
+
+Reflex::POE::Session allows a Reflex::Object to receive events from a
+specific POE::Session instance, identified by the session's ID. In
+the future, it may also limit the events it may see, for better
+performance.
+
+TODO - Complete the documentatin.
+
+=head1 GETTING HELP
+
+L<Reflex/GETTING HELP>
+
+=head1 ACKNOWLEDGEMENTS
+
+L<Reflex/ACKNOWLEDGEMENTS>
+
+=head1 SEE ALSO
+
+L<Reflex> and L<Reflex/SEE ALSO>
+
+=head1 BUGS
+
+L<Reflex/BUGS>
+
+=head1 CORE AUTHORS
+
+L<Reflex/CORE AUTHORS>
+
+=head1 OTHER CONTRIBUTORS
+
+L<Reflex/OTHER CONTRIBUTORS>
+
+=head1 COPYRIGHT AND LICENSE
+
+L<Reflex/COPYRIGHT AND LICENSE>
+
+=cut
66 lib/Reflex/POE/Wheel.pm
View
@@ -91,3 +91,69 @@ no Moose;
__PACKAGE__->meta()->make_immutable();
1;
+
+__END__
+
+=head1 NAME
+
+Reflex::POE::Wheel - Base class for POE::Wheel wrappers.
+
+=head1 SYNOPSIS
+
+# Not a complete example. Consider looking at the source for
+# Reflex::POE::Wheel::Run, which subclasses Reflex::POE::Wheel.
+
+TODO - Need an example.
+
+=head1 DESCRIPTION
+
+Reflex::POE::Wheel is a base class for POE::Wheel wrappers.
+Subclasses configure Reflex::POE::Wheel to provide the proper
+POE::Wheel constructor parameters. Additional configuration converts
+the POE::Wheel events into Reflex::Object events.
+
+Methods are not yet converted automatically. It seems more sensible
+to provide a native Reflex::Object interface, although one could
+certainly use Moose's "handles" attribute optioni to pass the wheel's
+methods through the wrapper.
+
+TODO - Complete the documentation.
+
+=head2 wheel_id
+
+Return the internal wheel's ID.
+
+=head2 demolish_wheel
+
+Cause the internal wheel to be demolished. Provided as a method since
+some wheels may require special handling.
+
+=head1 GETTING HELP
+
+L<Reflex/GETTING HELP>
+
+=head1 ACKNOWLEDGEMENTS
+
+L<Reflex/ACKNOWLEDGEMENTS>
+
+=head1 SEE ALSO
+
+L<Reflex> and L<Reflex/SEE ALSO>
+
+=head1 BUGS
+
+L<Reflex/BUGS>
+
+=head1 CORE AUTHORS
+
+L<Reflex/CORE AUTHORS>
+
+=head1 OTHER CONTRIBUTORS
+
+L<Reflex/OTHER CONTRIBUTORS>
+
+=head1 COPYRIGHT AND LICENSE
+
+L<Reflex/COPYRIGHT AND LICENSE>
+
+=cut
101 lib/Reflex/POE/Wheel/Run.pm
View
@@ -84,23 +84,17 @@ sub valid_params {
use Reflex::PID;
has sigchild_watcher => (
- isa => 'Reflex::PID|Undef',
- is => 'rw',
+ isa => 'Reflex::PID|Undef',
+ is => 'rw',
+ traits => ['Reflex::Trait::Observer'],
+ role => 'sigchld',
);
sub BUILD {
my $self = shift;
$self->sigchild_watcher(
- Reflex::PID->new(
- pid => $self->wheel()->PID(),
- observers => [
- {
- observer => $self,
- role => 'sigchld',
- },
- ],
- )
+ Reflex::PID->new(pid => $self->wheel()->PID())
);
}
@@ -117,3 +111,88 @@ no Moose;
__PACKAGE__->meta()->make_immutable();
1;
+
+__END__
+
+=head1 NAME
+
+Reflex::POE::Wheel::Run - Allow a Reflex class to represent POE::Wheel::Run.
+
+=head1 SYNOPSIS
+
+# Not a complete example. Please see eg-07-wheel-run.pl or even
+# better eg-08-observer-trait.pl for working examples.
+
+ has child => (
+ traits => ['Reflex::Trait::Observer'],
+ isa => 'Reflex::POE::Wheel::Run|Undef',
+ is => 'rw',
+ );
+
+ sub BUILD {
+ my $self = shift;
+ $self->child(
+ Reflex::POE::Wheel::Run->new(
+ Program => "$^X -wle 'print qq[pid(\$\$) moo(\$_)] for 1..10; exit'",
+ )
+ );
+ }
+
+ sub on_child_stdout {
+ my ($self, $args) = @_;
+ print "stdout: $args->{output}\n";
+ }
+
+ sub on_child_close {
+ my ($self, $args) = @_;
+ print "child closed all output\n";
+ }
+
+ sub on_child_signal {
+ my ($self, $args) = @_;
+ print "child $args->{pid} exited: $args->{exit}\n";
+ $self->child(undef);
+ }
+
+TODO - Needs a better example.
+
+=head1 DESCRIPTION
+
+Reflex::POE::Wheel::Run represents an enhanced POE::Wheel::Run object.
+Currently, the sole enhancement is to also wait for SIGCHLD and notify
+observers when the child process exits.
+
+TODO - Further improvement would be to defer the SIGCHLD notification
+until all child output has been received.
+
+TODO - Complete the API and documentation.
+
+=head1 GETTING HELP
+
+L<Reflex/GETTING HELP>
+
+=head1 ACKNOWLEDGEMENTS
+
+L<Reflex/ACKNOWLEDGEMENTS>
+
+=head1 SEE ALSO
+
+L<Reflex> and L<Reflex/SEE ALSO>
+
+=head1 BUGS
+
+L<Reflex/BUGS>
+
+=head1 CORE AUTHORS
+
+L<Reflex/CORE AUTHORS>
+
+=head1 OTHER CONTRIBUTORS
+
+L<Reflex/OTHER CONTRIBUTORS>
+
+=head1 COPYRIGHT AND LICENSE
+
+L<Reflex/COPYRIGHT AND LICENSE>
+
+=cut
107 lib/Reflex/Role/Object.pm
View
@@ -190,7 +190,7 @@ sub BUILD {
# TODO - Better way to detect CodeRef?
if (ref($callback) eq "CODE") {
my $member = $setup->name();
- $self->$member( $callback->() ); # TODO - Proper parameters!
+ $self->$member( $callback->($self) ); # TODO - Proper parameters!
next;
}
@@ -600,3 +600,108 @@ no Moose;
#__PACKAGE__->meta()->make_immutable();
1;
+
+__END__
+
+=head1 NAME
+
+Reflex::Object - Give an object reflexes.
+
+=head1 SYNOPSIS
+
+ {
+ package Object;
+ use Moose;
+ with 'Reflex::Role::Object';
+ ...;
+ }
+
+=head1 DESCRIPTION
+
+Reflex::Role::Object provides the implementation of Reflex::Object as
+a role.
+
+TODO - Complete the documentation, including examples for all methods.
+
+=head2 observe
+
+Observe events emitted by another object. See L</emit>.
+
+=head2 observe_role
+
+Observe events emitted by another object, and call this object's
+methods based on the other object's role or purpose within the owner.
+
+TODO - The name "role" conflicts with Moose concepts, and so it may be
+renamed. Alternative names are welcome.
+
+=head2 isnt_observed
+
+Stop observing this object. Used during shutdown and destruction to
+end all observers watching the object.
+
+=head2 is_observed
+
+The object is being observed. A helper method for observe().
+
+TODO - Consider making private?
+
+=head2 emit
+
+The object emits an event, and all observers will be notified.
+
+=head2 shutdown
+
+The object is being shut down. It will ignore() all objects that it
+is observing, and all objects observing it will ignore() it as well.
+
+=head2 ignore
+
+Stop watching an object, or specific events emitted by the object.
+
+=head2 call_gate
+
+POE helper method that ensures a method is called within the object's
+associated POE session context. Returns 1 if the method is already
+being executed in the proper context. Returns 0 if it's not, and
+re-invokes the method within the proper session.
+
+=head2 run_within_session
+
+POE helper method that invokes a method or coderef within the Reflex
+object's associated POE session context. Primarily used during BUILD
+methods for event watchers, which are invoked in the caller's context.
+
+=head2 run_all
+
+Run all Reflex objects until they destruct.
+
+=head1 GETTING HELP
+
+L<Reflex/GETTING HELP>
+
+=head1 ACKNOWLEDGEMENTS
+
+L<Reflex/ACKNOWLEDGEMENTS>
+
+=head1 SEE ALSO
+
+L<Reflex> and L<Reflex/SEE ALSO>
+
+=head1 BUGS
+
+L<Reflex/BUGS>
+
+=head1 CORE AUTHORS
+
+L<Reflex/CORE AUTHORS>
+
+=head1 OTHER CONTRIBUTORS
+
+L<Reflex/OTHER CONTRIBUTORS>
+
+=head1 COPYRIGHT AND LICENSE
+
+L<Reflex/COPYRIGHT AND LICENSE>
+
+=cut
86 lib/Reflex/Role/UdpPeer.pm
View
@@ -1,5 +1,3 @@
-# A UDP peer implemented as a role.
-
package Reflex::Role::UdpPeer;
use Moose::Role;
with 'Reflex::Role::Object';
@@ -11,8 +9,10 @@ has port => (
);
has handle => (
- isa => 'Reflex::Handle|Undef',
- is => 'rw',
+ isa => 'Reflex::Handle|Undef',
+ is => 'rw',
+ traits => ['Reflex::Trait::Observer'],
+ role => 'remote',
);
has max_datagram_size => (
@@ -31,12 +31,6 @@ after 'BUILD' => sub {
LocalPort => $self->port(),
),
rd => 1,
- observers => [
- {
- observer => $self,
- role => 'remote',
- }
- ],
)
);
undef;
@@ -96,3 +90,75 @@ no Moose;
#__PACKAGE__->meta()->make_immutable();
1;
+
+__END__
+
+=head1 NAME
+
+Reflex::Role::UdpPeer - Turn an object into a UDP network peer.
+
+=head1 SYNOPSIS
+
+ {
+ package Reflex::UdpPeer::Echo;
+ use Moose;
+ with 'Reflex::Role::UdpPeer';
+
+ sub on_my_datagram {
+ my ($self, $args) = @_;
+ my $data = $args->{datagram};
+
+ if ($data =~ /^\s*shutdown\s*$/) {
+ $self->destruct();
+ return;
+ }
+
+ $self->send(
+ datagram => $data,
+ remote_addr => $args->{remote_addr},
+ );
+ }
+
+ sub on_my_error {
+ my ($self, $args) = @_;
+ warn "$args->{op} error $args->{errnum}: $args->{errstr}";
+ $self->destruct();
+ }
+ }
+
+=head1 DESCRIPTION
+
+Reflex::Role::UdpPeer is an alternative to inheriting from
+Reflex::UdpPeer directly.
+
+TODO - Complete the documentation.
+
+=head1 GETTING HELP
+
+L<Reflex/GETTING HELP>
+
+=head1 ACKNOWLEDGEMENTS
+
+L<Reflex/ACKNOWLEDGEMENTS>
+
+=head1 SEE ALSO
+
+L<Reflex> and L<Reflex/SEE ALSO>
+
+=head1 BUGS
+
+L<Reflex/BUGS>
+
+=head1 CORE AUTHORS
+
+L<Reflex/CORE AUTHORS>
+
+=head1 OTHER CONTRIBUTORS
+
+L<Reflex/OTHER CONTRIBUTORS>
+
+=head1 COPYRIGHT AND LICENSE
+
+L<Reflex/COPYRIGHT AND LICENSE>
+
+=cut
51 lib/Reflex/Signal.pm
View
@@ -104,3 +104,54 @@ no Moose;
__PACKAGE__->meta()->make_immutable();
1;
+
+__END__
+
+=head1 NAME
+
+Reflex::Signal - Generic signal observer and base class for specific ones.
+
+=head1 SYNOPSIS
+
+TODO - Sorry, not yet. This class works (see the source for
+Reflex::PID, which extends it), but the API is not firm.
+
+=head1 DESCRIPTION
+
+Reflex::Signal is a generig signal observer. Objects may use it to be
+notified when the OS sends signals. It may also be extended to handle
+nuanced semantics of more specific signals.
+
+TODO - Complete the API.
+
+TODO - Complete the documentation.
+
+=head1 GETTING HELP
+
+L<Reflex/GETTING HELP>
+
+=head1 ACKNOWLEDGEMENTS
+
+L<Reflex/ACKNOWLEDGEMENTS>
+
+=head1 SEE ALSO
+
+L<Reflex> and L<Reflex/SEE ALSO>
+
+=head1 BUGS
+
+L<Reflex/BUGS>
+
+=head1 CORE AUTHORS
+
+L<Reflex/CORE AUTHORS>
+
+=head1 OTHER CONTRIBUTORS
+
+L<Reflex/OTHER CONTRIBUTORS>
+
+=head1 COPYRIGHT AND LICENSE
+
+L<Reflex/COPYRIGHT AND LICENSE>
+
+=cut
62 lib/Reflex/Timer.pm
View
@@ -72,3 +72,65 @@ no Moose;
__PACKAGE__->meta()->make_immutable();
1;
+
+__END__
+
+=head1 NAME
+
+Reflex::Timer - Observe the passage of time.
+
+=head1 SYNOPSIS
+
+# Not a complete program. Many of the examples use Reflex::Timer.
+# You can't throw a stone without hitting one.
+
+ sub object_method {
+ my ($self, $args) = @_;
+
+ $self->timer(
+ Reflex::Timer->new(
+ interval => 1,
+ auto_repeat => 1,
+ )
+ );
+ );
+
+=head1 DESCRIPTION
+
+Reflex::Timer emits events to mark the passage of time.
+
+TODO - Complete the API. It's currently very incomplete. It only
+handles relative delays via its "interval" constructor parameter, and
+automatic repeat via "auto_repeat".
+
+TODO - Complete the documentation.
+
+=head1 GETTING HELP
+
+L<Reflex/GETTING HELP>
+
+=head1 ACKNOWLEDGEMENTS
+
+L<Reflex/ACKNOWLEDGEMENTS>
+
+=head1 SEE ALSO
+
+L<Reflex> and L<Reflex/SEE ALSO>
+
+=head1 BUGS
+
+L<Reflex/BUGS>
+
+=head1 CORE AUTHORS
+
+L<Reflex/CORE AUTHORS>
+
+=head1 OTHER CONTRIBUTORS
+
+L<Reflex/OTHER CONTRIBUTORS>
+
+=head1 COPYRIGHT AND LICENSE
+
+L<Reflex/COPYRIGHT AND LICENSE>
+
+=cut
68 lib/Reflex/Trait/Emitter.pm
View
@@ -82,3 +82,71 @@ package Moose::Meta::Attribute::Custom::Trait::Reflex::Trait::Emitter;
sub register_implementation { 'Reflex::Trait::Emitter' }
1;
+
+__END__
+
+=head1 NAME
+
+Reflex::Trait::Emitter - Automatically emit events when values change.
+
+=head1 SYNOPSIS
+
+# Not a complete program. See examples eg-09-emitter-trait.pl and
+# eg-10-setup.pl for working examples.
+
+ {
+ package Counter;
+ use Moose;
+ extends 'Reflex::Object';
+ use Reflex::Trait::Emitter;
+
+ has count => (
+ traits => ['Reflex::Trait::Emitter'],
+ isa => 'Int',
+ is => 'rw',
+ default => 0,
+ );
+ }
+
+=head1 DESCRIPTION
+
+Reflex::Trait::Emitter allows an object to automatically emit an event
+when the value of its attribute changes. In the SYNOPSIS, changing
+the value of count() will cause the Counter object to emit a "count"
+event with the new count's value.
+
+Custom mutators may also use Reflex::Object's emit() method to
+announce changes. Reflex::Trait::Emitter is expected to handle many
+common scenarios.
+
+TODO - Complete the documentation.
+
+=head1 GETTING HELP
+
+L<Reflex/GETTING HELP>
+
+=head1 ACKNOWLEDGEMENTS
+
+L<Reflex/ACKNOWLEDGEMENTS>
+
+=head1 SEE ALSO
+
+L<Reflex> and L<Reflex/SEE ALSO>
+
+=head1 BUGS
+
+L<Reflex/BUGS>
+
+=head1 CORE AUTHORS
+
+L<Reflex/CORE AUTHORS>
+
+=head1 OTHER CONTRIBUTORS
+
+L<Reflex/OTHER CONTRIBUTORS>
+
+=head1 COPYRIGHT AND LICENSE
+
+L<Reflex/COPYRIGHT AND LICENSE>
+
+=cut
68 lib/Reflex/Trait/Observer.pm
View
@@ -94,3 +94,71 @@ package Moose::Meta::Attribute::Custom::Trait::Reflex::Trait::Observer;
sub register_implementation { 'Reflex::Trait::Observer' }
1;
+
+__END__
+
+=head1 NAME
+
+Reflex::Trait::Observer - Automatically observe Reflex objects.
+
+=head1 SYNOPSIS
+
+# Not a complete program. This example comes from Reflex's main
+# L<synopsis|Reflex/SYNOPSIS>.
+
+ has clock => (
+ isa => 'Reflex::Timer',
+ is => 'rw',
+ traits => [ 'Reflex::Trait::Observer' ],
+ setup => { interval => 1, auto_repeat => 1 },
+ );
+
+=head1 DESCRIPTION
+
+Reflex::Trait::Observer allows an object to automatically observe
+other objects it owns. In the SYNOPSIS, storing a Reflex::Timer in
+clock() allows the owner to observe the timer's events.
+
+Reflex::Object has explicit methods to do this, namely observe() and
+observe_role(), but they are more verbose.
+
+The "setup" attribute option provides default constructor parameters
+for the attribute. In the above example, clock() will by default
+contain
+
+ Reflex::Timer->new(interval => 1, auto_repeat => 1);
+
+In other words, it will emit an event ("tick") once per second until
+destroyed.
+
+TODO - Complete the documentation.
+
+=head1 GETTING HELP
+
+L<Reflex/GETTING HELP>
+
+=head1 ACKNOWLEDGEMENTS
+
+L<Reflex/ACKNOWLEDGEMENTS>
+
+=head1 SEE ALSO
+
+L<Reflex> and L<Reflex/SEE ALSO>
+
+=head1 BUGS
+
+L<Reflex/BUGS>
+
+=head1 CORE AUTHORS
+
+L<Reflex/CORE AUTHORS>
+
+=head1 OTHER CONTRIBUTORS
+
+L<Reflex/OTHER CONTRIBUTORS>
+
+=head1 COPYRIGHT AND LICENSE
+
+L<Reflex/COPYRIGHT AND LICENSE>
+
+=cut
110 lib/Reflex/UdpPeer.pm
View
@@ -1,5 +1,3 @@
-# A UDP peer.
-
package Reflex::UdpPeer;
use Moose;
with 'Reflex::Role::UdpPeer';
@@ -16,26 +14,118 @@ __END__
=head1 NAME
-Reflex::UdpPeer - Base class for reactive UDP peers.
+Reflex::UdpPeer - Base class for UDP networking peers.
+
+=head1 SYNOPSIS
+
+Inherit it.
+
+ {
+ package Reflex::UdpPeer::Echo;
+ use Moose;
+ extends 'Reflex::UdpPeer';
+
+ sub on_my_datagram {
+ my ($self, $args) = @_;
+ my $data = $args->{datagram};
+
+ if ($data =~ /^\s*shutdown\s*$/) {
+ $self->destruct();
+ return;
+ }
+
+ $self->send(
+ datagram => $data,
+ remote_addr => $args->{remote_addr},
+ );
+ }
+
+ sub on_my_error {
+ my ($self, $args) = @_;
+ warn "$args->{op} error $args->{errnum}: $args->{errstr}";
+ $self->destruct();
+ }
+ }
+
+Use it as a helper.
+
+ {
+ package Reflex::UdpPeer::Echo;
+ use Moose;
+ extends 'Reflex::Object';
+ use Reflex::UdpPeer;
+
+ has port => (
+ isa => 'Int',
+ is => 'ro',
+ );
+
+ has peer => (
+ isa => 'Reflex::UdpPeer|Undef',
+ is => 'rw',
+ traits => ['Reflex::Trait::Observer'],
+ setup => sub {
+ my $self = shift;
+ Reflex::UdpPeer->new(port => $self->port());
+ },
+ );
+
+ sub on_peer_datagram {
+ my ($self, $args) = @_;
+ my $data = $args->{datagram};
+
+ if ($data =~ /^\s*shutdown\s*$/) {
+ $self->peer(undef);
+ return;
+ }
+
+ $self->peer()->send(
+ datagram => $data,
+ remote_addr => $args->{remote_addr},
+ );
+ }
+
+ sub on_peer_error {
+ my ($self, $args) = @_;
+ warn "$args->{op} error $args->{errnum}: $args->{errstr}";
+ $self->peer(undef);
+ }
+ }
+
+Compose objects with its base role. See L<Reflex::Role::UdpPeer>.
=head1 DESCRIPTION
-Reflex::UdpPeer is a base class for reactive UDP peers. It takes all
-its functionality from Reflex::Role::UdpPeer, so please see that
-module for documentation.
+Reflex::UdpPeer is a base class for UDP network peers.
+
+TODO - Complete the documentation.
+
+=head1 GETTING HELP
+
+L<Reflex/GETTING HELP>
+
+=head1 ACKNOWLEDGEMENTS
+
+L<Reflex/ACKNOWLEDGEMENTS>
=head1 SEE ALSO
-Reflex::Role::UdpPeer - Documents Reflex::UdpPeer.
+L<Reflex> and L<Reflex/SEE ALSO>
=head1 BUGS
-TODO - Link to RT.
+L<Reflex/BUGS>
+
+=head1 CORE AUTHORS
-=head1 AUTHORS
+L<Reflex/CORE AUTHORS>
-Rocco Caputo.
+=head1 OTHER CONTRIBUTORS
+
+L<Reflex/OTHER CONTRIBUTORS>
=head1 COPYRIGHT AND LICENSE
+L<Reflex/COPYRIGHT AND LICENSE>
+
=cut
20 t/00_info.t
View
@@ -0,0 +1,20 @@
+#!/usr/bin/env perl
+
+package Satisfy::Moose;
+
+use warnings;
+use strict;
+
+use Test::More tests => 3;
+
+use_ok("Moose");
+use_ok("POE");
+use_ok("Reflex");
+
+diag(
+ "Testing Reflex $Reflex::VERSION, ",
+ "POE $POE::VERSION, ",
+ "Moose $Moose::VERSION, ",
+ "Perl $], ",
+ "$^X on $^O"
+);
Please sign in to comment.
Something went wrong with that request. Please try again.