Commit 36d2b512456d25d407f7103c897ed3a40c34a991

Initial stab at Reflex::Callback::Method.
  
2323# 5. All callback mechanisms may be specified by slightly verbose but
2424# unambiguous syntax.
2525
26# Ideally all the eg-*-rcb-*.pl examples will use the identical
27# ThingWithCallbacks. That class will have no custom callback logic
28# at all.
29
2630use warnings;
2731use strict;
2832use lib qw(../lib);
  
1#!/usr/bin/env perl
2
3# This example illustrates implicit and explicit callbacks via object
4# methods. A ThingWithCallbacks will call methods on objects defined
5# in this file.
6
7# Reflex::Callbacks and the Reflex::Callback helper classes will
8# abstract callbacks to fulfill a number of goals. The goals are
9# detailed in docs/requirements.otl and summarized in
10# eg/eg-20-rcb-callback.pl
11
12use warnings;
13use strict;
14use lib qw(../lib);
15
16# Create a thing that will invoke callbacks. This syntax uses
17# explicitly specified cb_method() callbacks. There is no
18# nonambiguous implicit syntax at this time. Suggestions are welcome.
19
20{
21 package Object;
22 use Moose;
23
24 use ExampleHelpers qw(eg_say);
25 use Reflex::Callbacks qw(cb_method);
26 use ThingWithCallbacks;
27
28 has callback_thing => ( is => 'rw', isa => 'ThingWithCallbacks' );
29
30 sub BUILD {
31 my $self = shift;
32
33 $self->callback_thing(
34 ThingWithCallbacks->new(
35 on_event => cb_method($self, "handle_event")
36 )
37 );
38 }
39
40 sub handle_event {
41 my ($self, $arg) = @_;
42 eg_say("object handled event");
43 }
44
45 sub run_thing {
46 my $self = shift;
47 $self->callback_thing()->run();
48 }
49}
50
51my $o = Object->new();
52$o->run_thing();
53
54__END__
55
56# cb_coderef() reduces context sensitivity at the expense of
57# verbosity.
58
59my $thing_two = ThingWithCallbacks->new(
60 on_event => cb_coderef(sub { eg_say("explicit callback invoked") }),
61);
62
63$thing_two->run();
64
65# cb_coderef is prototyped so it can replace "sub".
66
67my $thing_three = ThingWithCallbacks->new(
68 on_event => cb_coderef { eg_say("explicit callback (no sub) invoked") },
69);
70
71$thing_three->run();
72
73exit;
74
75__END__
76
77#!/usr/bin/env perl
78
79# As promised in eg-01-discrete-observer.pl, it's time to make the
80# syntax nicer and formal.
81#
82# Most syntaxes have two or three forms. The first is a simplified,
83# context-sensitive form for people who like concise and cryptic. The
84# second is a slightly more verbose, explicit form for people who
85# prefer clarity.
86
87use warnings;
88use strict;
89use lib qw(../lib);
90
91use ExampleHelpers qw(eg_say eg_object);
92
93# TODO - Some kind of :all or :default tag?
94use Reflex::Callbacks qw(
95 cb_class cb_coderef cb_method cb_object cb_promise cb_role
96);
97
98# Objects need to be stored somewhere, but we don't really care about
99# them. Push them onto a list, and forget about them.
100
101my @things;
102
103####################
104# Coderef callbacks.
105#
106# The most flexible callbacks are simply coderefs. They are clear,
107# concise, and allow develpers to emulate continuation-passing style
108# by abusing closures.
109#
110# Coderef callbacks are less suitable for object-oriented programs.
111# Using closures, developers can certainly thunk from coderefs to
112# objects, but this puts a repetitive burden on developers. See
113# method callbacks below for a more convenient way.
114
115# The simplified contextual style is a plain coderef.
116
117push @things, ThingWithCallbacks->new(
118 on_tick => sub { eg_say("simple coderef callback") },
119);
120
121# The explicit style uses cb_coderef() to identify the callback type.
122# Cb stands for Callback.
123
124push @things, ThingWithCallbacks->new(
125 on_tick => cb_coderef( sub { eg_say("explicit coderef callback") } ),
126);
127
128# Here is a second variant of cb_coderef() using the (&) prototype to
129# eliminate some punctuation and the "sub" keyword.
130
131push @things, ThingWithCallbacks->new(
132 on_tick => cb_coderef { eg_say("prototyped coderef callback") },
133);
134
135##########################
136# Object method callbacks.
137#
138# Invoking methods as callbacks is another popular choice. This is
139# often more convenient in object-oriented situations. Methods may be
140# invoked on objects or classes. The syntax is the same in Perl, so
141# there's no difference in Reflex.
142
143# The simplified contextual style uses an arrayref, containing the
144# object and method name. While it's a pair of values, we can't use a
145# hashref without invalidating the object by stringification.
146
147my $eg_object_1 = eg_object("simplified single event callback object");
148push @things, ThingWithCallbacks->new(
149 on_tick => [ $eg_object_1, "handler_method" ],
150);
151
152# The explicit style uses cb_method() to identify the callback type.
153
154my $eg_object_2 = eg_object("explicit single event callback object");
155push @things, ThingWithCallbacks->new(
156 on_tick => cb_method( $eg_object_1, "handler_method" ),
157);
158
159#############################
160# Multiple callbacks at once.
161#
162# The rest of the variants deal with assigning multiple callbacks to
163# a single object. The above forms will work well, but they involve
164# repetition that can feel tedious when a lot of events are handled.
165#
166# Consider the following example:
167#
168# my $bot = Reflex::IrcBot->new();
169# my $protocol = Reflex::Poco::IRC->new(
170# on_irc_001 => [ $bot, "handle_irc_connected" ],
171# on_irc_public => [ $bot, "handle_irc_public" ],
172# on_irc_msg => [ $bot, "handle_irc_private" ],
173# on_irc_notice => [ $bot, "handle_irc_notice" ],
174# # ... and a dozen other interesting IRC events ...
175# );
176#
177# The simplified syntax extends the simplified object syntx. The
178# scalar "method_name" is replaced by a list of method names or a map
179# of event names to method names.
180#
181# An arrayref is used when the handler methods and event names are
182# identical.
183#
184# This group of syntaxes specify multiple event names in their
185# callback definitions. They are all lumped under the "callbacks"
186# parameter.
187
188my $eg_object_3 = eg_object("simplified multiple method callbacks");
189push @things, ThingWithCallbacks->new(
190 callbacks => [ $eg_object_3, [qw( event_a event_b event_c )] ],
191);
192
193# A hashref is used to map event names to method names.
194
195my $eg_object_4 = eg_object("simplified multiple mapped methods");
196push @things, ThingWithCallbacks->new(
197 callbacks => [
198 $eg_object_3, {
199 event_a => "handler_method_a",
200 event_b => "handler_method_b",
201 event_c => "handler_method_c",
202 },
203 ],
204);
205
206# Multiple method callbacks may also be defined with explicit
207# syntaxes.
208
209my $eg_object_5 = eg_object("explicit multiple method callbacks");
210push @things, ThingWithCallbacks->new(
211 callbacks => cb_object(
212 $eg_object_5,
213 [qw( event_a event_b event_c)]
214 ),
215);
216
217my $eg_object_6 = eg_object("explicit multiple mapped methods");
218push @things, ThingWithCallbacks->new(
219 callbacks => cb_object(
220 $eg_object_6, {
221 event_a => "handler_method_a",
222 event_b => "handler_method_b",
223 event_c => "handler_method_c",
224 },
225 ),
226);
227
228#########################
229# Class method callbacks.
230#
231# Class methods may be called using the same syntaxes as object
232# method. As of this writing, the mechanisms for invokving class
233# methods are identical in Perl to those of invoking object methods.
234# An cb_class() utility function is provided for forward
235# compatibility. If the mechanisms were to diverge in a future
236# version of Perl, cb_class() would updated to accommodate the
237# change.
238
239# Examples aren't shown since they would look nearly identical to
240# previous ones.
241
242#######################
243# Role based callbacks.
244#
245# Role-based callbacks map an object's responses to its destination's
246# methods using a simple algorithm. Method names consist of a prefix
247# ("handle"), the sub-object's role (perhaps "dns"), and the
248# sub-object's event name ("answer") joined by underscores to become:
249# handle_dns_answer().
250#
251# In theory, each object performs a task or role that contributes to
252# the program as a whole. Larger, more complex objects are built by
253# gluing together smaller objects that perform simpler roles. For
254# example, a simple HTTP client might glue together some generic
255# objects like so:
256#
257# HTTP client
258# Keep-alive connection manager ("keepalive" object)
259# Asynchronous DNS resolver ("resolver" object)
260# Asynchronous TCP connector ("connector" object)
261# HTTP stream ("httpstream" object)
262# Asynchronous stream ("stream" object)
263# HTTP protocol ("http" object)
264#
265# At each level, the container object knows the interfaces for the
266# smaller objects within it. It can therefore assign the smaller
267# objects roles and implicitly handle their events by defining methods
268# with predictable names.
269
270# Currently there is only the explicit cb_role() function to define
271# roles. Implicit syntax is left for a future release.
272#
273# $eg_object_7->handle_ticker_tick() is called in response to the
274# following Reflex::Timer's "tick" event.
275
276my $eg_object_7 = eg_object("explicit role, explicit prefix");
277push @things, ThingWithCallbacks->new(
278 callbacks => cb_role($eg_object_7, "ticker", "handle"),
279);
280
281# The third parameter to cb_role() is the method prefix, which
282# defaults to "handle" if omitted. $eg_object_8's method
283# handle_ticker_tick() is called below. The "handle" is implied by
284# default.
285
286my $eg_object_8 = eg_object("explicit role, implicit prefix");
287push @things, ThingWithCallbacks->new(
288 callbacks => cb_role($eg_object_8, "ticker"),
289);
290
291######################
292# Promises or futures.
293#
294# Promises are the final callback mechanism Reflex supports. They are
295# defined by either not defining callbacks at all, or by defining
296# cb_promise() as the callbacks mechanism.
297#
298# Note however that this code will block. Nothing beyond it runs
299# until the while() loop finishes. Which may be "never". Other
300# caveats may apply.
301
302my $implicit_promisory_timer = ThingWithCallbacks->new();
303
304while (my $next_event = $implicit_promisory_timer->next_event()) {
305 eg_tell("implicit promisory timer generated event $next_event");
306}
307
308# People who dislike invisible logic might prefer cb_promise().
309#
310my $explicit_promisory_timer = ThingWithCallbacks->new(
311 callbacks => cb_promise(),
312);
313
314while (my $next_event = $explicit_promisory_timer->next_event()) {
315 eg_tell("explicit promisory timer generated event $next_event");
316}
317
318###############
319# Run the demo.
320
321Reflex::Object->run_all();
322exit;
  
1package Reflex::Callback::Method;
2
3use Moose;
4extends 'Reflex::Callback';
5
6has object => (
7 is => 'ro',
8 isa => 'Object',
9 weak_ref => 1,
10);
11
12has method_name => (
13 is => 'ro',
14 isa => 'Str',
15 required => 1,
16);
17
18sub deliver {
19 my $self = shift;
20 my $method_name = $self->method_name();
21 $self->object()->$method_name(@_);
22}
23
241;
  
1818#use Reflex::Callback::Class;
1919use Reflex::Callback::CodeRef;
2020#use Reflex::Callback::Emit; # For current Reflex compatibility
21#use Reflex::Callback::Method;
21use Reflex::Callback::Method;
2222#use Reflex::Callback::Object;
2323#use Reflex::Callback::Promise;
2424#use Reflex::Callback::Role;
6565 };
6666
6767sub cb_method {
68 die;
6968 my ($object, $method_name) = @_;
7069 return Reflex::Callback::Method->new(
71 object => $object,
70 object => $object,
7271 method_name => $method_name,
7372 );
7473}