/[cvs]/nfo/perl/libs/DesignPattern/Bridge.pm
ViewVC logotype

Contents of /nfo/perl/libs/DesignPattern/Bridge.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.13 - (show annotations)
Tue Jul 1 23:26:37 2003 UTC (20 years, 10 months ago) by joko
Branch: MAIN
CVS Tags: HEAD
Changes since 1.12: +12 -2 lines
croak to STDERR if module loading fails!

1 ## --------------------------------------------------------------------------------
2 ## $Id: Bridge.pm,v 1.12 2003/05/13 08:39:22 joko Exp $
3 ## --------------------------------------------------------------------------------
4 ## $Log: Bridge.pm,v $
5 ## Revision 1.12 2003/05/13 08:39:22 joko
6 ## autocalling constructor after instantiation
7 ## added pod documentation
8 ##
9 ## Revision 1.11 2003/02/21 08:38:21 joko
10 ## + additional checks
11 ## + raising exceptions
12 ##
13 ## Revision 1.10 2003/02/20 20:50:32 joko
14 ## + small exception handling: now inheriting from little Exception object
15 ##
16 ## Revision 1.9 2003/02/18 18:35:30 joko
17 ## + encapsulated/abstracted some more functionality: sub load_single
18 ##
19 ## Revision 1.8 2003/02/14 14:20:05 joko
20 ## + modified mixin behaviour
21 ##
22 ## Revision 1.7 2003/02/11 10:34:19 joko
23 ## + loaded module may now lack 'mixin::with' declaration
24 ## + this gets us the possibility to load modules from any perl namespace
25 ## + enabled this mechanism
26 ##
27 ## Revision 1.6 2003/02/09 16:22:51 joko
28 ## + pseudo constructor mechanism via options
29 ##
30 ## Revision 1.5 2003/01/31 01:19:50 root
31 ## + fixed: doesn't need Log::Dispatch any more, but uses it if available
32 ##
33 ## Revision 1.4 2003/01/20 16:55:15 joko
34 ## + sub mixinPackage
35 ## + sub include
36 ##
37 ## Revision 1.3 2002/12/16 19:57:12 joko
38 ## + sub unload
39 ##
40 ## Revision 1.2 2002/12/15 02:06:15 joko
41 ## + feature to be able to specify module in non-perl-style when loading plugins: e.g. $process->load('Setup/Storage')
42 ##
43 ## Revision 1.1 2002/12/13 21:46:29 joko
44 ## + initial check-in
45 ##
46 ## --------------------------------------------------------------------------------
47
48
49 package DesignPattern::Bridge;
50
51 use strict;
52 use warnings;
53
54 use base qw(
55 DesignPattern::Object
56 DesignPattern::Exception
57 );
58
59
60 use Data::Dumper;
61
62 =pod
63
64 =head1 NAME
65
66 DesignPattern::Bridge
67
68
69 =head1 DESCRIPTION
70
71 This acts as a generic backplane for plugins using "Mix-in inheritance".
72
73
74 =head2 BACKGROUND
75
76 Mix-in inheritance
77 Please visit [http://citeseer.nj.nec.com/bracha90mixinbased.html].
78
79 [...]
80 Abstract: The diverse inheritance mechanisms provided by Smalltalk, Beta,
81 and CLOS are interpreted as different uses of a single underlying construct.
82 Smalltalk and Beta differ primarily in the direction of class hierarchy growth.
83 These inheritance mechanisms are subsumed in a new inheritance model
84 based on composition of mixins, or abstract subclasses. This form of
85 inheritance can also encode a CLOS multiple-inheritance hierarchy, although
86 changes to the encoded hierarchy that would violate... (Update)
87 [...]
88
89 ...level, and can naturally span component boundaries. Jiazzi supports
90 the composition of class extending components; e.g. mixins [1]. Mixins
91 and cyclic component linking can be combined into an open class pattern,
92 which allows independent features that cross cut class...
93
94 =head3 History of "mixins"
95
96 =head4 G. Bracha, W. Cook. Mixin-based inheritance.
97
98 G. Bracha and W. Cook, "Mixin-Based Inheritance", ECOOP/OOPSLA 1990, 303-311.
99 G. Bracha, W. Cook. Mixin-based inheritance. In OOPSLA/ECOOP '90 Conference Proceedings. ACM SIGPLAN Notices 25, 10 (Oct. 1990).
100
101 @inproceedings{ bracha90mixinbased,
102 author = "Gilad Bracha and William Cook",
103 title = "Mixin-Based Inheritance",
104 booktitle = "Proceedings of the Conference on Object-Oriented Programming: Systems, Languages, and Applications / Proceedings of the European Conference on Object-Oriented Programming",
105 publisher = "ACM Press",
106 address = "Ottawa, Canada",
107 editor = "Norman Meyrowitz",
108 pages = "303--311",
109 year = "1990",
110 url = "citeseer.nj.nec.com/bracha90mixinbased.html" }
111
112 =head4 D. Duggan and C. Sourelis. Mixin modules.
113
114 http://users.hol.gr/~csourelis/thesis.html
115
116 @misc{ duggan96mixin,
117 author = "D. Duggan and C. Sourelis",
118 title = "Mixin modules",
119 text = "D. Duggan and C. Sourelis. Mixin modules. In Intl. Conf. on Functional
120 Programming, Philadelphia, May 1996. ACM Press.",
121 year = "1996",
122 url = "citeseer.nj.nec.com/sourelis95mixin.html" }
123
124 =head4 Google on your own:
125
126 http://www.google.com/search?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&q=mix-in+inheritance
127 http://www.google.com/search?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&q=Moo86+mixins
128
129
130 =head3 Discussion
131
132 http://citeseer.nj.nec.com/context/6117/0
133
134 =head2 References
135
136 The Jigsaw Framework:
137 http://citeseer.nj.nec.com/bracha92programming.html
138
139 http://citeseer.nj.nec.com/114070.html
140 http://citeseer.nj.nec.com/445396.html
141 http://citeseer.nj.nec.com/tichelaar97coordination.html
142 http://citeseer.nj.nec.com/meijler98beyond.html
143
144 http://citeseer.nj.nec.com/89291.html
145 http://citeseer.nj.nec.com/sousa91runtime.html
146 http://citeseer.nj.nec.com/banavar95application.html
147 http://citeseer.nj.nec.com/sourelis95mixin.html
148 http://citeseer.nj.nec.com/hirschowitz02mixin.html
149
150 Java: http://csis.pace.edu/~bergin/patterns/multipleinheritance.html
151 C++: http://www.oofile.com.au/oofdoc/samples/ooftst19.htm
152
153 =head3 Related
154
155 http://citeseer.nj.nec.com/nrelated/6117/23339
156
157
158 =head3 Traits - Composable Units of Behavior
159
160 via: http://citeseer.nj.nec.com/context/22076/0
161
162 Traits: Composable Units of Behavior - Nathanael Schrli Stphane (Correct)
163 ....is not expressive enough to factor out common features (i.e. instance
164 variables and methods) shared by classes in a complex hierarchy. As a
165 consequence, language designers have proposed various forms of multiple
166 inheritance [Mey88] Kee89] Str86] as well as other mechanisms, such as
167 mixins [Moo86] BC90] FKF98] that allow classes to be composed incrementally
168 from sets of features. Despite the passage of nearly twenty years, neither
169 multiple inheritance nor mixins have achieved wide acceptance [Tai96]
170 Summarizing Alan Snyder s contribution to the inheritance panel discussion
171 at OOPSLA ....
172
173 ....complete. But as a unit of reuse, a class should be small. These properties
174 often conflict. Furthermore, the role of classes as instance generators requires
175 that each class have a unique place in the class hierarchy, whereas units of
176 reuse should be applicable at arbitrary places. Moon s Flavors [Moo86] were
177 an early attempt to address this problem: Flavors are small, not necessarily
178 complete, and they can be mixed in at arbitrary places in the class hierarchy.
179 More sophisticated notions of mixins were subsequently developed by Bracha
180 and Cook [BC90] and Flatt, Krishnamurthi and Felleisen ....
181
182 David A. Moon. Object-oriented programming with flavors. In Proceedings
183 OOPSLA '86, ACM SIGPLAN Notices, pages 1--8, November 1986.
184 Published as Proceedings OOPSLA '86, ACM SIGPLAN Notices, volume 21, number 11.
185
186
187 from: http://citeseer.nj.nec.com/566972.html
188
189 Abstract: Inheritance is the fundamental reuse mechanism in object-oriented
190 programming languages; its most prominent variants are single inheritance,
191 multiple inheritance, and mixin inheritance. In the first part of this paper,
192 we identify and illustrate the conceptual and practical reusability problems
193 that arise with these forms of inheritance. We then present a simple
194 compositional model for structuring object-oriented programs, which we call traits.
195 Traits are essentially groups of methods... (Update)
196
197
198 =head3 Hybrid - A Language for Programming with Active Objects
199
200 http://citeseer.nj.nec.com/561934.html
201 http://citeseer.nj.nec.com/nierstrasz92tour.html
202 http://www.iam.unibe.ch/~scg/Archive/NFS/cao.html
203
204 =head3 Active Objects and Oberon
205
206
207 =head2 DETAILS
208
209 This attempts to be a runtime wrapper around mixin.pm, written by Michael G Schwern
210 and available on CPAN.
211 Please visit:
212 http://magnonel.guild.net/~schwern/talks/Design_Patterns/full_slides/slide036.html
213
214
215 =head2 NOTES
216
217 ## ======== object inheritance ========
218
219 2002-12:
220 TODO / REFACTORING PROPOSAL
221 leading from Data::Storage to code abstracted out into this module - DesignPattern::Bridge
222 - this is no inheritance and it doesn't have to be
223 - implement this module as a bridge to its sub-modules
224 - use the BridgePattern (http://c2.com/cgi/wiki?BridgePattern)
225 Using patterns was already successfully done with Data::Storage::Handler
226 by implementing the AdapterPattern (http://c2.com/cgi/wiki?AdapterPattern)
227 with Perl's AUTOLOAD-mechanism
228 - try to use Perl's "tie" command to implement this functionality here instead of using AUTOLOAD!
229 - sub getChildNodes
230 - sub run
231
232 2003-02-11, joko: Does this have anything in parallel with CPAN's Class::Inner? No!
233
234
235 =head1 TODO
236
237 o use Class::Loader
238 o rename to mixin::runtime?
239
240
241 =cut
242
243
244 # get logger instance
245 my $logger = eval { Log::Dispatch::Config->instance; };
246
247 my $meta;
248
249
250 sub DEBUG { 1 }
251
252
253 ## ======== object constructor ========
254 sub new {
255 my $invocant = shift;
256 my $class = ref($invocant) || $invocant;
257 my @args = ();
258 @_ && (@args = @_);
259 $logger->debug( __PACKAGE__ . "->new(@args)" ) if $logger;
260 my $self = { @_ };
261
262 # trace
263 #print "class: $class", "\n";
264
265 # create instance
266 bless $self, $class;
267
268 # NEW: 2003-04-16
269 $self->constructor() if $self->can('constructor');
270
271 return $self;
272 }
273
274
275 ## ======== method overrider ========
276 sub AUTOLOAD2 {
277
278 my $self = shift;
279 our $AUTOLOAD;
280
281 ##print "AUTOLOAD\n";
282
283 my $method = $AUTOLOAD;
284 $method =~ s/^.*:://;
285
286 $logger->debug( __PACKAGE__ . "->" . $method . "(@_)" . " (AUTOLOAD called, not dispatched)" ) if $logger;
287
288 ## ->DESTROY would - if not declared - trigger an AUTOLOAD also
289 return if $method =~ m/::DESTROY$/;
290
291 ## if ($self->_filter_AUTOLOAD($method)) {
292 ## $self->_accessStorage();
293 ## $self->{STORAGEHANDLE}->$method(@_);
294 ## }
295
296 }
297
298 sub _getPluginPackage {
299 my $self = shift;
300 my $modulename_load = shift;
301
302 # substitute slashes through double double-colons to load modules perl-style
303 $modulename_load =~ s/\//::/g;
304
305 # build full package name
306 my $self_classname = ref $self;
307 # name
308 my $package = $modulename_load;
309
310 # if package is absolute, cut away prefix ('/' or '::')
311 if ($package !~ s/^:://) {
312 # else: prefix with base classname if above name is relative (lacks of '/' or '::')
313 $package = $self_classname . '::' . $package
314 }
315
316 return $package;
317 }
318
319 sub load {
320
321 my $self = shift;
322 my $modulename = shift;
323 my $options = shift;
324
325 if (ref $modulename eq 'ARRAY') {
326 foreach (@$modulename) {
327 $self->load_single($_, $options);
328 }
329 } else {
330 $self->load_single($modulename, $options);
331 }
332
333 }
334
335 sub load_single {
336
337 my $self = shift;
338 my $modulename_load = shift;
339
340 my $options = shift;
341
342 my $self_modulename = ref $self;
343 my $package = $self->_getPluginPackage($modulename_load);
344
345 if ($meta->{loaded}->{$package}) {
346 return 1;
347 }
348
349 #$logger->info( __PACKAGE__ . "->load: $package" ) if $logger;
350 #$logger->info( __PACKAGE__ . "->load: $self_modulename" ) if $logger;
351 $logger->debug( $self_modulename . "->load: $package\t[via " . __PACKAGE__ . "]" ) if $logger;
352
353 # this is the module testing phase - use mixin doesn't seem to propagate errors by default
354 eval("use $package;");
355 $self->checkExceptions();
356
357 =pod
358 if ($@) {
359 $meta->{loaded}->{$package} = 0;
360 # include caller information
361 my @caller = caller;
362 my $caller_msg = $caller[1] . ':' . $caller[2];
363 my $msg = __PACKAGE__ . "->load: $@ ($caller_msg)";
364 if ($logger) {
365 $logger->error($msg);
366 } else {
367 print $msg, "\n";
368 }
369 }
370 =cut
371
372 #print "ref-1: ", ref $self, "\n";
373 #print "ref-2: ", ref $self::SUPER, "\n";
374
375 # V1:
376 #bless $self, $package;
377
378 # V2:
379 $self->mixinPackage($package);
380
381 if (my $method = $options->{method}) {
382 $self->$method();
383 }
384
385 return 1;
386
387 }
388
389 sub mixinPackage {
390 my $self = shift;
391 my $package = shift;
392
393 # switch into foreign package and prepare for mixin
394 $self->mixin_prepare($package);
395
396 # switch into local package (scope which uses DesignPattern::Bridge) and mixin plugin-module
397 $self->mixin_do($package);
398
399 }
400
401 # TODO: maybe refactor to DesignPattern::Object? what about the '$logger'?
402 sub mixin_prepare {
403 my $self = shift;
404 my $package = shift;
405 my $self_classname = ref $self;
406 eval("package $package; use mixin::with '$self_classname';");
407
408 # FIXME: --- this is redundant ---
409 if ($@) {
410 $meta->{loaded}->{$package} = 0;
411 my $msg = __PACKAGE__ . "->load: $@";
412 print STDERR $msg, "\n" if DEBUG;
413 $logger->error( $msg ) if $logger;
414 } else {
415 $meta->{loaded}->{$package} = 1;
416 }
417 # FIXME: --- this is redundant ---
418
419 }
420
421 sub mixin_do {
422 my $self = shift;
423 my $package = shift;
424 # switch into foreign package and mixin plugin-module
425 my $self_classname = ref $self;
426 eval("package $self_classname; use mixin '$package';");
427 #eval("use mixin_all '$package';");
428
429 # FIXME: --- this is redundant ---
430 if ($@) {
431 $meta->{loaded}->{$package} = 0;
432 $logger->error( __PACKAGE__ . "->load: $@" ) if $logger;
433 } else {
434 $meta->{loaded}->{$package} = 1;
435 }
436 # FIXME: --- this is redundant ---
437
438 }
439
440 sub unload {
441
442 my $self = shift;
443 my $modulename_unload = shift;
444
445 my $package = $self->_getPluginPackage($modulename_unload);
446
447 if ($meta->{loaded}->{$package}) {
448 $meta->{loaded}->{$package} = 0;
449 my $where = __PACKAGE__ . ':' . __LINE__;
450 $logger->debug( __PACKAGE__ . "->unload: FIXME: DESTROY object is not implemented at '$where'." ) if $logger;
451 }
452
453 }
454
455
456 sub boot {
457 my $self = shift;
458 $self->_abstract_function('boot');
459 }
460
461 sub include {
462 my $self = shift;
463 my $includefile = shift;
464 my $package = shift;
465
466 # pre-flight checks
467 if (!$includefile) {
468 $self->raiseException('Filename for inclusion was empty.');
469 return;
470 }
471
472 # go for it ...
473 eval("require '$includefile';");
474 # ... and handle errors afterwards catching every message from perl itself ...
475 return if $self->checkExceptions();
476
477 # ... otherwise continue assuming everything is fine
478 $self->mixinPackage($package) if $package;
479
480 }
481
482 1;
483 __END__

MailToCvsAdmin">MailToCvsAdmin
ViewVC Help
Powered by ViewVC 1.1.26 RSS 2.0 feed