--- nfo/perl/libs/DesignPattern/Bridge.pm 2002/12/16 19:57:12 1.3 +++ nfo/perl/libs/DesignPattern/Bridge.pm 2003/05/13 08:39:22 1.12 @@ -1,7 +1,39 @@ ## -------------------------------------------------------------------------------- -## $Id: Bridge.pm,v 1.3 2002/12/16 19:57:12 joko Exp $ +## $Id: Bridge.pm,v 1.12 2003/05/13 08:39:22 joko Exp $ ## -------------------------------------------------------------------------------- ## $Log: Bridge.pm,v $ +## Revision 1.12 2003/05/13 08:39:22 joko +## autocalling constructor after instantiation +## added pod documentation +## +## Revision 1.11 2003/02/21 08:38:21 joko +## + additional checks +## + raising exceptions +## +## Revision 1.10 2003/02/20 20:50:32 joko +## + small exception handling: now inheriting from little Exception object +## +## Revision 1.9 2003/02/18 18:35:30 joko +## + encapsulated/abstracted some more functionality: sub load_single +## +## Revision 1.8 2003/02/14 14:20:05 joko +## + modified mixin behaviour +## +## Revision 1.7 2003/02/11 10:34:19 joko +## + loaded module may now lack 'mixin::with' declaration +## + this gets us the possibility to load modules from any perl namespace +## + enabled this mechanism +## +## Revision 1.6 2003/02/09 16:22:51 joko +## + pseudo constructor mechanism via options +## +## Revision 1.5 2003/01/31 01:19:50 root +## + fixed: doesn't need Log::Dispatch any more, but uses it if available +## +## Revision 1.4 2003/01/20 16:55:15 joko +## + sub mixinPackage +## + sub include +## ## Revision 1.3 2002/12/16 19:57:12 joko ## + sub unload ## @@ -19,44 +51,221 @@ use strict; use warnings; -use base qw( DesignPattern::Object ); +use base qw( + DesignPattern::Object + DesignPattern::Exception +); + use Data::Dumper; -## ======== object inheritance ======== +=pod + +=head1 NAME + + DesignPattern::Bridge + + +=head1 DESCRIPTION + + This acts as a generic backplane for plugins using "Mix-in inheritance". + + +=head2 BACKGROUND + + Mix-in inheritance + Please visit [http://citeseer.nj.nec.com/bracha90mixinbased.html]. + + [...] + Abstract: The diverse inheritance mechanisms provided by Smalltalk, Beta, + and CLOS are interpreted as different uses of a single underlying construct. + Smalltalk and Beta differ primarily in the direction of class hierarchy growth. + These inheritance mechanisms are subsumed in a new inheritance model + based on composition of mixins, or abstract subclasses. This form of + inheritance can also encode a CLOS multiple-inheritance hierarchy, although + changes to the encoded hierarchy that would violate... (Update) + [...] + + ...level, and can naturally span component boundaries. Jiazzi supports + the composition of class extending components; e.g. mixins [1]. Mixins + and cyclic component linking can be combined into an open class pattern, + which allows independent features that cross cut class... + +=head3 History of "mixins" + +=head4 G. Bracha, W. Cook. Mixin-based inheritance. + + G. Bracha and W. Cook, "Mixin-Based Inheritance", ECOOP/OOPSLA 1990, 303-311. + G. Bracha, W. Cook. Mixin-based inheritance. In OOPSLA/ECOOP '90 Conference Proceedings. ACM SIGPLAN Notices 25, 10 (Oct. 1990). + + @inproceedings{ bracha90mixinbased, + author = "Gilad Bracha and William Cook", + title = "Mixin-Based Inheritance", + booktitle = "Proceedings of the Conference on Object-Oriented Programming: Systems, Languages, and Applications / Proceedings of the European Conference on Object-Oriented Programming", + publisher = "ACM Press", + address = "Ottawa, Canada", + editor = "Norman Meyrowitz", + pages = "303--311", + year = "1990", + url = "citeseer.nj.nec.com/bracha90mixinbased.html" } + +=head4 D. Duggan and C. Sourelis. Mixin modules. + + http://users.hol.gr/~csourelis/thesis.html + + @misc{ duggan96mixin, + author = "D. Duggan and C. Sourelis", + title = "Mixin modules", + text = "D. Duggan and C. Sourelis. Mixin modules. In Intl. Conf. on Functional + Programming, Philadelphia, May 1996. ACM Press.", + year = "1996", + url = "citeseer.nj.nec.com/sourelis95mixin.html" } + +=head4 Google on your own: + + http://www.google.com/search?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&q=mix-in+inheritance + http://www.google.com/search?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&q=Moo86+mixins + + +=head3 Discussion + + http://citeseer.nj.nec.com/context/6117/0 + +=head2 References + + The Jigsaw Framework: + http://citeseer.nj.nec.com/bracha92programming.html + + http://citeseer.nj.nec.com/114070.html + http://citeseer.nj.nec.com/445396.html + http://citeseer.nj.nec.com/tichelaar97coordination.html + http://citeseer.nj.nec.com/meijler98beyond.html + + http://citeseer.nj.nec.com/89291.html + http://citeseer.nj.nec.com/sousa91runtime.html + http://citeseer.nj.nec.com/banavar95application.html + http://citeseer.nj.nec.com/sourelis95mixin.html + http://citeseer.nj.nec.com/hirschowitz02mixin.html + + Java: http://csis.pace.edu/~bergin/patterns/multipleinheritance.html + C++: http://www.oofile.com.au/oofdoc/samples/ooftst19.htm + +=head3 Related + + http://citeseer.nj.nec.com/nrelated/6117/23339 + + +=head3 Traits - Composable Units of Behavior + + via: http://citeseer.nj.nec.com/context/22076/0 + + Traits: Composable Units of Behavior - Nathanael Schrli Stphane (Correct) + ....is not expressive enough to factor out common features (i.e. instance + variables and methods) shared by classes in a complex hierarchy. As a + consequence, language designers have proposed various forms of multiple + inheritance [Mey88] Kee89] Str86] as well as other mechanisms, such as + mixins [Moo86] BC90] FKF98] that allow classes to be composed incrementally + from sets of features. Despite the passage of nearly twenty years, neither + multiple inheritance nor mixins have achieved wide acceptance [Tai96] + Summarizing Alan Snyder s contribution to the inheritance panel discussion + at OOPSLA .... + + ....complete. But as a unit of reuse, a class should be small. These properties + often conflict. Furthermore, the role of classes as instance generators requires + that each class have a unique place in the class hierarchy, whereas units of + reuse should be applicable at arbitrary places. Moon s Flavors [Moo86] were + an early attempt to address this problem: Flavors are small, not necessarily + complete, and they can be mixed in at arbitrary places in the class hierarchy. + More sophisticated notions of mixins were subsequently developed by Bracha + and Cook [BC90] and Flatt, Krishnamurthi and Felleisen .... + + David A. Moon. Object-oriented programming with flavors. In Proceedings + OOPSLA '86, ACM SIGPLAN Notices, pages 1--8, November 1986. + Published as Proceedings OOPSLA '86, ACM SIGPLAN Notices, volume 21, number 11. + + + from: http://citeseer.nj.nec.com/566972.html + + Abstract: Inheritance is the fundamental reuse mechanism in object-oriented + programming languages; its most prominent variants are single inheritance, + multiple inheritance, and mixin inheritance. In the first part of this paper, + we identify and illustrate the conceptual and practical reusability problems + that arise with these forms of inheritance. We then present a simple + compositional model for structuring object-oriented programs, which we call traits. + Traits are essentially groups of methods... (Update) + + +=head3 Hybrid - A Language for Programming with Active Objects + + http://citeseer.nj.nec.com/561934.html + http://citeseer.nj.nec.com/nierstrasz92tour.html + http://www.iam.unibe.ch/~scg/Archive/NFS/cao.html + +=head3 Active Objects and Oberon + + +=head2 DETAILS + + This attempts to be a runtime wrapper around mixin.pm, written by Michael G Schwern + and available on CPAN. + Please visit: + http://magnonel.guild.net/~schwern/talks/Design_Patterns/full_slides/slide036.html + + +=head2 NOTES + + ## ======== object inheritance ======== + + 2002-12: + TODO / REFACTORING PROPOSAL + leading from Data::Storage to code abstracted out into this module - DesignPattern::Bridge + - this is no inheritance and it doesn't have to be + - implement this module as a bridge to its sub-modules + - use the BridgePattern (http://c2.com/cgi/wiki?BridgePattern) + Using patterns was already successfully done with Data::Storage::Handler + by implementing the AdapterPattern (http://c2.com/cgi/wiki?AdapterPattern) + with Perl's AUTOLOAD-mechanism + - try to use Perl's "tie" command to implement this functionality here instead of using AUTOLOAD! + - sub getChildNodes + - sub run + + 2003-02-11, joko: Does this have anything in parallel with CPAN's Class::Inner? No! + + +=head1 TODO + + o use Class::Loader + o rename to mixin::runtime? + + +=cut -# TODO: -# - this is no inheritance and it doesn't have to be -# - implement this module as a bridge to its sub-modules -# - use the BridgePattern (http://c2.com/cgi/wiki?BridgePattern) -# Using patterns was already successfully done with Data::Storage::Handler -# by implementing the AdapterPattern (http://c2.com/cgi/wiki?AdapterPattern) -# with Perl's AUTOLOAD-mechanism -# - try to use Perl's "tie" command to implement this functionality here instead of using AUTOLOAD! -# - sub getChildNodes -# - sub run # get logger instance -my $logger = Log::Dispatch::Config->instance; +my $logger = eval { Log::Dispatch::Config->instance; }; my $meta; ## ======== object constructor ======== - sub new { - my $invocant = shift; - my $class = ref($invocant) || $invocant; - my @args = (); - @_ && (@args = @_); - $logger->debug( __PACKAGE__ . "->new(@args)" ); - my $self = { @_ }; +sub new { + my $invocant = shift; + my $class = ref($invocant) || $invocant; + my @args = (); + @_ && (@args = @_); + $logger->debug( __PACKAGE__ . "->new(@args)" ) if $logger; + my $self = { @_ }; + + # trace #print "class: $class", "\n"; - bless $self, $class; - ##if (my $bizWorks = shift) { - ##$self->boot($bizWorks); - ##} - - return $self; - } + + # create instance + bless $self, $class; + + # NEW: 2003-04-16 + $self->constructor() if $self->can('constructor'); + + return $self; +} ## ======== method overrider ======== @@ -70,7 +279,7 @@ my $method = $AUTOLOAD; $method =~ s/^.*:://; - $logger->debug( __PACKAGE__ . "->" . $method . "(@_)" . " (AUTOLOAD called, not dispatched)" ); + $logger->debug( __PACKAGE__ . "->" . $method . "(@_)" . " (AUTOLOAD called, not dispatched)" ) if $logger; ## ->DESTROY would - if not declared - trigger an AUTOLOAD also return if $method =~ m/::DESTROY$/; @@ -91,32 +300,70 @@ # build full package name my $self_classname = ref $self; - my $package = $self_classname . '::' . $modulename_load; + # name + my $package = $modulename_load; + + # if package is absolute, cut away prefix ('/' or '::') + if ($package !~ s/^:://) { + # else: prefix with base classname if above name is relative (lacks of '/' or '::') + $package = $self_classname . '::' . $package + } + return $package; } sub load { my $self = shift; + my $modulename = shift; + my $options = shift; + + if (ref $modulename eq 'ARRAY') { + foreach (@$modulename) { + $self->load_single($_, $options); + } + } else { + $self->load_single($modulename, $options); + } + + } + + sub load_single { + + my $self = shift; my $modulename_load = shift; + my $options = shift; + + my $self_modulename = ref $self; my $package = $self->_getPluginPackage($modulename_load); if ($meta->{loaded}->{$package}) { return 1; } - $logger->info( __PACKAGE__ . "->load: $package" ); + #$logger->info( __PACKAGE__ . "->load: $package" ) if $logger; + #$logger->info( __PACKAGE__ . "->load: $self_modulename" ) if $logger; + $logger->debug( $self_modulename . "->load: $package\t[via " . __PACKAGE__ . "]" ) if $logger; # this is the module testing phase - use mixin doesn't seem to propagate errors by default eval("use $package;"); + $self->checkExceptions(); + +=pod if ($@) { $meta->{loaded}->{$package} = 0; # include caller information my @caller = caller; my $caller_msg = $caller[1] . ':' . $caller[2]; - $logger->error( __PACKAGE__ . "->load: $@ ($caller_msg)" ); + my $msg = __PACKAGE__ . "->load: $@ ($caller_msg)"; + if ($logger) { + $logger->error($msg); + } else { + print $msg, "\n"; + } } +=cut #print "ref-1: ", ref $self, "\n"; #print "ref-2: ", ref $self::SUPER, "\n"; @@ -125,19 +372,63 @@ #bless $self, $package; # V2: + $self->mixinPackage($package); + + if (my $method = $options->{method}) { + $self->$method(); + } + + return 1; + + } + + sub mixinPackage { + my $self = shift; + my $package = shift; + + # switch into foreign package and prepare for mixin + $self->mixin_prepare($package); + + # switch into local package (scope which uses DesignPattern::Bridge) and mixin plugin-module + $self->mixin_do($package); + + } + + # TODO: maybe refactor to DesignPattern::Object? what about the '$logger'? + sub mixin_prepare { + my $self = shift; + my $package = shift; + my $self_classname = ref $self; + eval("package $package; use mixin::with '$self_classname';"); + + # FIXME: --- this is redundant --- + if ($@) { + $meta->{loaded}->{$package} = 0; + $logger->error( __PACKAGE__ . "->load: $@" ) if $logger; + } else { + $meta->{loaded}->{$package} = 1; + } + # FIXME: --- this is redundant --- + + } + + sub mixin_do { + my $self = shift; + my $package = shift; # switch into foreign package and mixin plugin-module my $self_classname = ref $self; eval("package $self_classname; use mixin '$package';"); #eval("use mixin_all '$package';"); + + # FIXME: --- this is redundant --- if ($@) { $meta->{loaded}->{$package} = 0; - $logger->error( __PACKAGE__ . "->load: $@" ); + $logger->error( __PACKAGE__ . "->load: $@" ) if $logger; } else { $meta->{loaded}->{$package} = 1; } + # FIXME: --- this is redundant --- - return 1; - } sub unload { @@ -150,7 +441,7 @@ if ($meta->{loaded}->{$package}) { $meta->{loaded}->{$package} = 0; my $where = __PACKAGE__ . ':' . __LINE__; - $logger->debug( __PACKAGE__ . "->unload: FIXME: DESTROY object is not implemented at '$where'." ); + $logger->debug( __PACKAGE__ . "->unload: FIXME: DESTROY object is not implemented at '$where'." ) if $logger; } } @@ -160,5 +451,27 @@ my $self = shift; $self->_abstract_function('boot'); } + + sub include { + my $self = shift; + my $includefile = shift; + my $package = shift; + + # pre-flight checks + if (!$includefile) { + $self->raiseException('Filename for inclusion was empty.'); + return; + } + + # go for it ... + eval("require '$includefile';"); + # ... and handle errors afterwards catching every message from perl itself ... + return if $self->checkExceptions(); + + # ... otherwise continue assuming everything is fine + $self->mixinPackage($package) if $package; + + } 1; +__END__