Commit 49d1ae16ab8185ccf1c8335d3b7d64e6a3c9bf1a

Implement three forms of object-based callback, via rcb_object().
  
11#!/usr/bin/env perl
22
3# This example illustrates implicit and explicit callbacks via object
4# methods. A ThingWithCallbacks will call methods on objects defined
5# in this file.
3# This example illustrates explicit callbacks via object methods. A
4# ThingWithCallbacks will call methods on objects defined in this
5# file.
66
77# Reflex::Callbacks and the Reflex::Callback helper classes will
88# abstract callbacks to fulfill a number of goals. The goals are
  
1#!/usr/bin/env perl
2
3# This example illustrates explicit callbacks via objects, where
4# callback events are mapped to handlers by name. Methods may be
5# named after the events they handle, or they may differ.
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_object() callbacks and a scalar for the
18# methods list. cb_method() would be slightly more efficient in this
19# case, but cb_object() also works.
20#
21# There is no nonambiguous implicit syntax at this time. Suggestions
22# for one are welcome.
23
24{
25 package ScalarHandlerObject;
26 use Moose;
27
28 use ExampleHelpers qw(eg_say);
29 use Reflex::Callbacks qw(cb_object);
30 use ThingWithCallbacks;
31
32 has callback_thing => ( is => 'rw', isa => 'ThingWithCallbacks' );
33
34 sub BUILD {
35 my $self = shift;
36
37 $self->callback_thing(
38 ThingWithCallbacks->new(
39 cb_object($self, "on_event"),
40 )
41 );
42 }
43
44 sub on_event {
45 my ($self, $arg) = @_;
46 eg_say("scalar object handled event");
47 }
48
49 sub run_thing {
50 my $self = shift;
51 $self->callback_thing()->run();
52 }
53}
54
55my $sho = ScalarHandlerObject->new();
56$sho->run_thing();
57
58# In this case, an object handles a list of callbacks. Each callback
59# method is named after the event it handles.
60#
61# There is no nonambiguous implicit syntax for this either, but
62# suggestions are welcome.
63
64{
65 package ArrayHandlerObject;
66 use Moose;
67
68 use ExampleHelpers qw(eg_say);
69 use Reflex::Callbacks qw(cb_object);
70 use ThingWithCallbacks;
71
72 has callback_thing => ( is => 'rw', isa => 'ThingWithCallbacks' );
73
74 sub BUILD {
75 my $self = shift;
76
77 $self->callback_thing(
78 ThingWithCallbacks->new(
79 cb_object($self, ["on_event"]),
80 )
81 );
82 }
83
84 sub on_event {
85 my ($self, $arg) = @_;
86 eg_say("array object handled event");
87 }
88
89 sub run_thing {
90 my $self = shift;
91 $self->callback_thing()->run();
92 }
93}
94
95my $aho = ArrayHandlerObject->new();
96$aho->run_thing();
97
98# In this case, an object handles a hash of callbacks. Hash keys are
99# event names, and the values are the corresponding handler method
100# names. The hash gives classes flexibility in the methods they use.
101#
102# There is no nonambiguous implicit syntax for this either, but
103# suggestions are welcome.
104
105{
106 package HashHandlerObject;
107 use Moose;
108
109 use ExampleHelpers qw(eg_say);
110 use Reflex::Callbacks qw(cb_object);
111 use ThingWithCallbacks;
112
113 has callback_thing => ( is => 'rw', isa => 'ThingWithCallbacks' );
114
115 sub BUILD {
116 my $self = shift;
117
118 $self->callback_thing(
119 ThingWithCallbacks->new(
120 cb_object($self, { on_event => "handle_event" }),
121 )
122 );
123 }
124
125 sub handle_event {
126 my ($self, $arg) = @_;
127 eg_say("hash object handled event");
128 }
129
130 sub run_thing {
131 my $self = shift;
132 $self->callback_thing()->run();
133 }
134}
135
136my $hho = HashHandlerObject->new();
137$hho->run_thing();
138
139__END__
140
141# cb_coderef() reduces context sensitivity at the expense of
142# verbosity.
143
144my $thing_two = ThingWithCallbacks->new(
145 on_event => cb_coderef(sub { eg_say("explicit callback invoked") }),
146);
147
148$thing_two->run();
149
150# cb_coderef is prototyped so it can replace "sub".
151
152my $thing_three = ThingWithCallbacks->new(
153 on_event => cb_coderef { eg_say("explicit callback (no sub) invoked") },
154);
155
156$thing_three->run();
157
158exit;
159
160__END__
161
162#!/usr/bin/env perl
163
164# As promised in eg-01-discrete-observer.pl, it's time to make the
165# syntax nicer and formal.
166#
167# Most syntaxes have two or three forms. The first is a simplified,
168# context-sensitive form for people who like concise and cryptic. The
169# second is a slightly more verbose, explicit form for people who
170# prefer clarity.
171
172use warnings;
173use strict;
174use lib qw(../lib);
175
176use ExampleHelpers qw(eg_say eg_object);
177
178# TODO - Some kind of :all or :default tag?
179use Reflex::Callbacks qw(
180 cb_class cb_coderef cb_method cb_object cb_promise cb_role
181);
182
183# Objects need to be stored somewhere, but we don't really care about
184# them. Push them onto a list, and forget about them.
185
186my @things;
187
188####################
189# Coderef callbacks.
190#
191# The most flexible callbacks are simply coderefs. They are clear,
192# concise, and allow develpers to emulate continuation-passing style
193# by abusing closures.
194#
195# Coderef callbacks are less suitable for object-oriented programs.
196# Using closures, developers can certainly thunk from coderefs to
197# objects, but this puts a repetitive burden on developers. See
198# method callbacks below for a more convenient way.
199
200# The simplified contextual style is a plain coderef.
201
202push @things, ThingWithCallbacks->new(
203 on_tick => sub { eg_say("simple coderef callback") },
204);
205
206# The explicit style uses cb_coderef() to identify the callback type.
207# Cb stands for Callback.
208
209push @things, ThingWithCallbacks->new(
210 on_tick => cb_coderef( sub { eg_say("explicit coderef callback") } ),
211);
212
213# Here is a second variant of cb_coderef() using the (&) prototype to
214# eliminate some punctuation and the "sub" keyword.
215
216push @things, ThingWithCallbacks->new(
217 on_tick => cb_coderef { eg_say("prototyped coderef callback") },
218);
219
220##########################
221# Object method callbacks.
222#
223# Invoking methods as callbacks is another popular choice. This is
224# often more convenient in object-oriented situations. Methods may be
225# invoked on objects or classes. The syntax is the same in Perl, so
226# there's no difference in Reflex.
227
228# The simplified contextual style uses an arrayref, containing the
229# object and method name. While it's a pair of values, we can't use a
230# hashref without invalidating the object by stringification.
231
232my $eg_object_1 = eg_object("simplified single event callback object");
233push @things, ThingWithCallbacks->new(
234 on_tick => [ $eg_object_1, "handler_method" ],
235);
236
237# The explicit style uses cb_method() to identify the callback type.
238
239my $eg_object_2 = eg_object("explicit single event callback object");
240push @things, ThingWithCallbacks->new(
241 on_tick => cb_method( $eg_object_1, "handler_method" ),
242);
243
244#############################
245# Multiple callbacks at once.
246#
247# The rest of the variants deal with assigning multiple callbacks to
248# a single object. The above forms will work well, but they involve
249# repetition that can feel tedious when a lot of events are handled.
250#
251# Consider the following example:
252#
253# my $bot = Reflex::IrcBot->new();
254# my $protocol = Reflex::Poco::IRC->new(
255# on_irc_001 => [ $bot, "handle_irc_connected" ],
256# on_irc_public => [ $bot, "handle_irc_public" ],
257# on_irc_msg => [ $bot, "handle_irc_private" ],
258# on_irc_notice => [ $bot, "handle_irc_notice" ],
259# # ... and a dozen other interesting IRC events ...
260# );
261#
262# The simplified syntax extends the simplified object syntx. The
263# scalar "method_name" is replaced by a list of method names or a map
264# of event names to method names.
265#
266# An arrayref is used when the handler methods and event names are
267# identical.
268#
269# This group of syntaxes specify multiple event names in their
270# callback definitions. They are all lumped under the "callbacks"
271# parameter.
272
273my $eg_object_3 = eg_object("simplified multiple method callbacks");
274push @things, ThingWithCallbacks->new(
275 callbacks => [ $eg_object_3, [qw( event_a event_b event_c )] ],
276);
277
278# A hashref is used to map event names to method names.
279
280my $eg_object_4 = eg_object("simplified multiple mapped methods");
281push @things, ThingWithCallbacks->new(
282 callbacks => [
283 $eg_object_3, {
284 event_a => "handler_method_a",
285 event_b => "handler_method_b",
286 event_c => "handler_method_c",
287 },
288 ],
289);
290
291# Multiple method callbacks may also be defined with explicit
292# syntaxes.
293
294my $eg_object_5 = eg_object("explicit multiple method callbacks");
295push @things, ThingWithCallbacks->new(
296 callbacks => cb_object(
297 $eg_object_5,
298 [qw( event_a event_b event_c)]
299 ),
300);
301
302my $eg_object_6 = eg_object("explicit multiple mapped methods");
303push @things, ThingWithCallbacks->new(
304 callbacks => cb_object(
305 $eg_object_6, {
306 event_a => "handler_method_a",
307 event_b => "handler_method_b",
308 event_c => "handler_method_c",
309 },
310 ),
311);
312
313#########################
314# Class method callbacks.
315#
316# Class methods may be called using the same syntaxes as object
317# method. As of this writing, the mechanisms for invokving class
318# methods are identical in Perl to those of invoking object methods.
319# An cb_class() utility function is provided for forward
320# compatibility. If the mechanisms were to diverge in a future
321# version of Perl, cb_class() would updated to accommodate the
322# change.
323
324# Examples aren't shown since they would look nearly identical to
325# previous ones.
326
327#######################
328# Role based callbacks.
329#
330# Role-based callbacks map an object's responses to its destination's
331# methods using a simple algorithm. Method names consist of a prefix
332# ("handle"), the sub-object's role (perhaps "dns"), and the
333# sub-object's event name ("answer") joined by underscores to become:
334# handle_dns_answer().
335#
336# In theory, each object performs a task or role that contributes to
337# the program as a whole. Larger, more complex objects are built by
338# gluing together smaller objects that perform simpler roles. For
339# example, a simple HTTP client might glue together some generic
340# objects like so:
341#
342# HTTP client
343# Keep-alive connection manager ("keepalive" object)
344# Asynchronous DNS resolver ("resolver" object)
345# Asynchronous TCP connector ("connector" object)
346# HTTP stream ("httpstream" object)
347# Asynchronous stream ("stream" object)
348# HTTP protocol ("http" object)
349#
350# At each level, the container object knows the interfaces for the
351# smaller objects within it. It can therefore assign the smaller
352# objects roles and implicitly handle their events by defining methods
353# with predictable names.
354
355# Currently there is only the explicit cb_role() function to define
356# roles. Implicit syntax is left for a future release.
357#
358# $eg_object_7->handle_ticker_tick() is called in response to the
359# following Reflex::Timer's "tick" event.
360
361my $eg_object_7 = eg_object("explicit role, explicit prefix");
362push @things, ThingWithCallbacks->new(
363 callbacks => cb_role($eg_object_7, "ticker", "handle"),
364);
365
366# The third parameter to cb_role() is the method prefix, which
367# defaults to "handle" if omitted. $eg_object_8's method
368# handle_ticker_tick() is called below. The "handle" is implied by
369# default.
370
371my $eg_object_8 = eg_object("explicit role, implicit prefix");
372push @things, ThingWithCallbacks->new(
373 callbacks => cb_role($eg_object_8, "ticker"),
374);
375
376######################
377# Promises or futures.
378#
379# Promises are the final callback mechanism Reflex supports. They are
380# defined by either not defining callbacks at all, or by defining
381# cb_promise() as the callbacks mechanism.
382#
383# Note however that this code will block. Nothing beyond it runs
384# until the while() loop finishes. Which may be "never". Other
385# caveats may apply.
386
387my $implicit_promisory_timer = ThingWithCallbacks->new();
388
389while (my $next_event = $implicit_promisory_timer->next_event()) {
390 eg_tell("implicit promisory timer generated event $next_event");
391}
392
393# People who dislike invisible logic might prefer cb_promise().
394#
395my $explicit_promisory_timer = ThingWithCallbacks->new(
396 callbacks => cb_promise(),
397);
398
399while (my $next_event = $explicit_promisory_timer->next_event()) {
400 eg_tell("explicit promisory timer generated event $next_event");
401}
402
403###############
404# Run the demo.
405
406Reflex::Object->run_all();
407exit;
408
409
410
411
412__END__
413
414#!/usr/bin/env perl
415
416# As promised in eg-01-discrete-observer.pl, it's time to make the
417# syntax nicer and formal.
418#
419# Most syntaxes have two or three forms. The first is a simplified,
420# context-sensitive form for people who like concise and cryptic. The
421# second is a slightly more verbose, explicit form for people who
422# prefer clarity.
423
424use warnings;
425use strict;
426use lib qw(../lib);
427
428use ExampleHelpers qw(eg_say eg_object);
429
430# TODO - Some kind of :all or :default tag?
431use Reflex::Callbacks qw(
432 cb_class cb_coderef cb_method cb_object cb_promise cb_role
433);
434
435# Objects need to be stored somewhere, but we don't really care about
436# them. Push them onto a list, and forget about them.
437
438my @things;
439
440####################
441# Coderef callbacks.
442#
443# The most flexible callbacks are simply coderefs. They are clear,
444# concise, and allow develpers to emulate continuation-passing style
445# by abusing closures.
446#
447# Coderef callbacks are less suitable for object-oriented programs.
448# Using closures, developers can certainly thunk from coderefs to
449# objects, but this puts a repetitive burden on developers. See
450# method callbacks below for a more convenient way.
451
452# The simplified contextual style is a plain coderef.
453
454push @things, ThingWithCallbacks->new(
455 on_tick => sub { eg_say("simple coderef callback") },
456);
457
458# The explicit style uses cb_coderef() to identify the callback type.
459# Cb stands for Callback.
460
461push @things, ThingWithCallbacks->new(
462 on_tick => cb_coderef( sub { eg_say("explicit coderef callback") } ),
463);
464
465# Here is a second variant of cb_coderef() using the (&) prototype to
466# eliminate some punctuation and the "sub" keyword.
467
468push @things, ThingWithCallbacks->new(
469 on_tick => cb_coderef { eg_say("prototyped coderef callback") },
470);
471
472##########################
473# Object method callbacks.
474#
475# Invoking methods as callbacks is another popular choice. This is
476# often more convenient in object-oriented situations. Methods may be
477# invoked on objects or classes. The syntax is the same in Perl, so
478# there's no difference in Reflex.
479
480# The simplified contextual style uses an arrayref, containing the
481# object and method name. While it's a pair of values, we can't use a
482# hashref without invalidating the object by stringification.
483
484my $eg_object_1 = eg_object("simplified single event callback object");
485push @things, ThingWithCallbacks->new(
486 on_tick => [ $eg_object_1, "handler_method" ],
487);
488
489# The explicit style uses cb_method() to identify the callback type.
490
491my $eg_object_2 = eg_object("explicit single event callback object");
492push @things, ThingWithCallbacks->new(
493 on_tick => cb_method( $eg_object_1, "handler_method" ),
494);
495
496#############################
497# Multiple callbacks at once.
498#
499# The rest of the variants deal with assigning multiple callbacks to
500# a single object. The above forms will work well, but they involve
501# repetition that can feel tedious when a lot of events are handled.
502#
503# Consider the following example:
504#
505# my $bot = Reflex::IrcBot->new();
506# my $protocol = Reflex::Poco::IRC->new(
507# on_irc_001 => [ $bot, "handle_irc_connected" ],
508# on_irc_public => [ $bot, "handle_irc_public" ],
509# on_irc_msg => [ $bot, "handle_irc_private" ],
510# on_irc_notice => [ $bot, "handle_irc_notice" ],
511# # ... and a dozen other interesting IRC events ...
512# );
513#
514# The simplified syntax extends the simplified object syntx. The
515# scalar "method_name" is replaced by a list of method names or a map
516# of event names to method names.
517#
518# An arrayref is used when the handler methods and event names are
519# identical.
520#
521# This group of syntaxes specify multiple event names in their
522# callback definitions. They are all lumped under the "callbacks"
523# parameter.
524
525my $eg_object_3 = eg_object("simplified multiple method callbacks");
526push @things, ThingWithCallbacks->new(
527 callbacks => [ $eg_object_3, [qw( event_a event_b event_c )] ],
528);
529
530# A hashref is used to map event names to method names.
531
532my $eg_object_4 = eg_object("simplified multiple mapped methods");
533push @things, ThingWithCallbacks->new(
534 callbacks => [
535 $eg_object_3, {
536 event_a => "handler_method_a",
537 event_b => "handler_method_b",
538 event_c => "handler_method_c",
539 },
540 ],
541);
542
543# Multiple method callbacks may also be defined with explicit
544# syntaxes.
545
546my $eg_object_5 = eg_object("explicit multiple method callbacks");
547push @things, ThingWithCallbacks->new(
548 callbacks => cb_object(
549 $eg_object_5,
550 [qw( event_a event_b event_c)]
551 ),
552);
553
554my $eg_object_6 = eg_object("explicit multiple mapped methods");
555push @things, ThingWithCallbacks->new(
556 callbacks => cb_object(
557 $eg_object_6, {
558 event_a => "handler_method_a",
559 event_b => "handler_method_b",
560 event_c => "handler_method_c",
561 },
562 ),
563);
564
565#########################
566# Class method callbacks.
567#
568# Class methods may be called using the same syntaxes as object
569# method. As of this writing, the mechanisms for invokving class
570# methods are identical in Perl to those of invoking object methods.
571# An cb_class() utility function is provided for forward
572# compatibility. If the mechanisms were to diverge in a future
573# version of Perl, cb_class() would updated to accommodate the
574# change.
575
576# Examples aren't shown since they would look nearly identical to
577# previous ones.
578
579#######################
580# Role based callbacks.
581#
582# Role-based callbacks map an object's responses to its destination's
583# methods using a simple algorithm. Method names consist of a prefix
584# ("handle"), the sub-object's role (perhaps "dns"), and the
585# sub-object's event name ("answer") joined by underscores to become:
586# handle_dns_answer().
587#
588# In theory, each object performs a task or role that contributes to
589# the program as a whole. Larger, more complex objects are built by
590# gluing together smaller objects that perform simpler roles. For
591# example, a simple HTTP client might glue together some generic
592# objects like so:
593#
594# HTTP client
595# Keep-alive connection manager ("keepalive" object)
596# Asynchronous DNS resolver ("resolver" object)
597# Asynchronous TCP connector ("connector" object)
598# HTTP stream ("httpstream" object)
599# Asynchronous stream ("stream" object)
600# HTTP protocol ("http" object)
601#
602# At each level, the container object knows the interfaces for the
603# smaller objects within it. It can therefore assign the smaller
604# objects roles and implicitly handle their events by defining methods
605# with predictable names.
606
607# Currently there is only the explicit cb_role() function to define
608# roles. Implicit syntax is left for a future release.
609#
610# $eg_object_7->handle_ticker_tick() is called in response to the
611# following Reflex::Timer's "tick" event.
612
613my $eg_object_7 = eg_object("explicit role, explicit prefix");
614push @things, ThingWithCallbacks->new(
615 callbacks => cb_role($eg_object_7, "ticker", "handle"),
616);
617
618# The third parameter to cb_role() is the method prefix, which
619# defaults to "handle" if omitted. $eg_object_8's method
620# handle_ticker_tick() is called below. The "handle" is implied by
621# default.
622
623my $eg_object_8 = eg_object("explicit role, implicit prefix");
624push @things, ThingWithCallbacks->new(
625 callbacks => cb_role($eg_object_8, "ticker"),
626);
627
628######################
629# Promises or futures.
630#
631# Promises are the final callback mechanism Reflex supports. They are
632# defined by either not defining callbacks at all, or by defining
633# cb_promise() as the callbacks mechanism.
634#
635# Note however that this code will block. Nothing beyond it runs
636# until the while() loop finishes. Which may be "never". Other
637# caveats may apply.
638
639my $implicit_promisory_timer = ThingWithCallbacks->new();
640
641while (my $next_event = $implicit_promisory_timer->next_event()) {
642 eg_tell("implicit promisory timer generated event $next_event");
643}
644
645# People who dislike invisible logic might prefer cb_promise().
646#
647my $explicit_promisory_timer = ThingWithCallbacks->new(
648 callbacks => cb_promise(),
649);
650
651while (my $next_event = $explicit_promisory_timer->next_event()) {
652 eg_tell("explicit promisory timer generated event $next_event");
653}
654
655###############
656# Run the demo.
657
658Reflex::Object->run_all();
659exit;
  
7373}
7474
7575sub cb_object {
76 die;
76 my ($object, $methods) = @_;
77
78 # They passed us a scalar. Emulate cb_methods().
79 return ($methods => cb_method(@_)) unless ref $methods;
80
81 if (ref($methods) eq "ARRAY") {
82 return map { ($_ => cb_method($object, $_)) } @$methods;
83 }
84
85 if (ref($methods) eq "HASH") {
86 return(
87 map { ($_ => cb_method($object, $methods->{$_})) }
88 keys %$methods
89 );
90 }
91
92 croak "cb_object with unknown methods type: $methods";
7793}
7894
7995sub cb_class {