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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.4 by joko, Mon Jan 20 16:55:15 2003 UTC revision 1.12 by joko, Tue May 13 08:39:22 2003 UTC
# Line 2  Line 2 
2  ##  $Id$  ##  $Id$
3  ## --------------------------------------------------------------------------------  ## --------------------------------------------------------------------------------
4  ##  $Log$  ##  $Log$
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  ##  Revision 1.4  2003/01/20 16:55:15  joko
34  ##  + sub mixinPackage  ##  + sub mixinPackage
35  ##  + sub include  ##  + sub include
# Line 23  package DesignPattern::Bridge; Line 51  package DesignPattern::Bridge;
51  use strict;  use strict;
52  use warnings;  use warnings;
53    
54  use base qw( DesignPattern::Object );  use base qw(
55      DesignPattern::Object
56      DesignPattern::Exception
57    );
58    
59    
60  use Data::Dumper;  use Data::Dumper;
61    
62  ## ========   object inheritance   ========  =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    
 # 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  
243    
244  # get logger instance  # get logger instance
245  my $logger = Log::Dispatch::Config->instance;  my $logger = eval { Log::Dispatch::Config->instance; };
246        
247  my $meta;  my $meta;
248    
249  ## ========   object constructor   ========  ## ========   object constructor   ========
250    sub new {  sub new {
251      my $invocant = shift;    my $invocant = shift;
252      my $class = ref($invocant) || $invocant;    my $class = ref($invocant) || $invocant;
253      my @args = ();    my @args = ();
254      @_ && (@args = @_);    @_ && (@args = @_);
255      $logger->debug( __PACKAGE__ . "->new(@args)" );    $logger->debug( __PACKAGE__ . "->new(@args)" ) if $logger;
256      my $self = { @_ };    my $self = { @_ };
257    
258      # trace
259      #print "class: $class", "\n";      #print "class: $class", "\n";
260      bless $self, $class;  
261      ##if (my $bizWorks = shift) {    # create instance
262        ##$self->boot($bizWorks);    bless $self, $class;
263      ##}  
264          # NEW: 2003-04-16
265      return $self;    $self->constructor() if $self->can('constructor');
266    }    
267      return $self;
268    }
269    
270    
271  ## ========   method overrider   ========  ## ========   method overrider   ========
# Line 74  my $meta; Line 279  my $meta;
279      my $method = $AUTOLOAD;      my $method = $AUTOLOAD;
280      $method =~ s/^.*:://;      $method =~ s/^.*:://;
281        
282      $logger->debug( __PACKAGE__ . "->" . $method . "(@_)" . " (AUTOLOAD called, not dispatched)" );      $logger->debug( __PACKAGE__ . "->" . $method . "(@_)" . " (AUTOLOAD called, not dispatched)" ) if $logger;
283    
284      ## ->DESTROY would - if not declared - trigger an AUTOLOAD also      ## ->DESTROY would - if not declared - trigger an AUTOLOAD also
285      return if $method =~ m/::DESTROY$/;      return if $method =~ m/::DESTROY$/;
# Line 95  my $meta; Line 300  my $meta;
300            
301      # build full package name      # build full package name
302      my $self_classname = ref $self;      my $self_classname = ref $self;
303      my $package = $self_classname . '::' . $modulename_load;        # name
304          my $package = $modulename_load;
305          
306          # if package is absolute, cut away prefix ('/' or '::')
307          if ($package !~ s/^:://) {
308            # else: prefix with base classname if above name is relative (lacks of '/' or '::')
309            $package = $self_classname . '::' . $package
310          }
311        
312      return $package;      return $package;
313    }    }
314        
315    sub load {    sub load {
316    
317      my $self = shift;      my $self = shift;
318        my $modulename = shift;
319        my $options = shift;
320    
321        if (ref $modulename eq 'ARRAY') {
322          foreach (@$modulename) {
323            $self->load_single($_, $options);
324          }
325        } else {
326          $self->load_single($modulename, $options);
327        }
328    
329      }
330    
331      sub load_single {
332    
333        my $self = shift;
334      my $modulename_load = shift;      my $modulename_load = shift;
335    
336        my $options = shift;
337    
338      my $self_modulename = ref $self;      my $self_modulename = ref $self;
339      my $package = $self->_getPluginPackage($modulename_load);      my $package = $self->_getPluginPackage($modulename_load);
340            
# Line 111  my $meta; Line 342  my $meta;
342        return 1;        return 1;
343      }      }
344            
345      #$logger->info( __PACKAGE__ . "->load: $package" );      #$logger->info( __PACKAGE__ . "->load: $package" ) if $logger;
346      #$logger->info( __PACKAGE__ . "->load: $self_modulename" );      #$logger->info( __PACKAGE__ . "->load: $self_modulename" ) if $logger;
347      $logger->debug( $self_modulename . "->load: $package\t[via " . __PACKAGE__ . "]" );      $logger->debug( $self_modulename . "->load: $package\t[via " . __PACKAGE__ . "]" ) if $logger;
348    
349      # this is the module testing phase - use mixin doesn't seem to propagate errors by default      # this is the module testing phase - use mixin doesn't seem to propagate errors by default
350      eval("use $package;");      eval("use $package;");
351        $self->checkExceptions();
352        
353    =pod    
354      if ($@) {      if ($@) {
355        $meta->{loaded}->{$package} = 0;        $meta->{loaded}->{$package} = 0;
356        # include caller information        # include caller information
357        my @caller = caller;        my @caller = caller;
358        my $caller_msg = $caller[1] . ':' . $caller[2];        my $caller_msg = $caller[1] . ':' . $caller[2];
359        $logger->error( __PACKAGE__ . "->load: $@ ($caller_msg)" );        my $msg =  __PACKAGE__ . "->load: $@ ($caller_msg)";
360          if ($logger) {
361            $logger->error($msg);
362          } else {
363            print $msg, "\n";
364          }
365      }      }
366    =cut
367    
368  #print "ref-1: ", ref $self, "\n";  #print "ref-1: ", ref $self, "\n";
369  #print "ref-2: ", ref $self::SUPER, "\n";  #print "ref-2: ", ref $self::SUPER, "\n";
# Line 132  my $meta; Line 372  my $meta;
372      #bless $self, $package;      #bless $self, $package;
373    
374      # V2:      # V2:
     # switch into foreign package and mixin plugin-module  
375      $self->mixinPackage($package);      $self->mixinPackage($package);
376        
377        if (my $method = $options->{method}) {
378          $self->$method();
379        }
380    
381      return 1;      return 1;
382            
383    }    }
384      
385      sub mixinPackage {
386        my $self = shift;
387        my $package = shift;
388        
389        # switch into foreign package and prepare for mixin
390        $self->mixin_prepare($package);
391    
392        # switch into local package (scope which uses DesignPattern::Bridge) and mixin plugin-module
393        $self->mixin_do($package);
394    
395      }
396    
397    # TODO: maybe refactor to DesignPattern::Object? what about the '$logger'?    # TODO: maybe refactor to DesignPattern::Object? what about the '$logger'?
398    sub mixinPackage {    sub mixin_prepare {
399        my $self = shift;
400        my $package = shift;
401        my $self_classname = ref $self;
402        eval("package $package; use mixin::with '$self_classname';");
403    
404        # FIXME: --- this is redundant ---
405        if ($@) {
406          $meta->{loaded}->{$package} = 0;
407          $logger->error( __PACKAGE__ . "->load: $@" ) if $logger;
408        } else {
409          $meta->{loaded}->{$package} = 1;
410        }
411        # FIXME: --- this is redundant ---
412    
413      }
414    
415      sub mixin_do {
416      my $self = shift;      my $self = shift;
417      my $package = shift;      my $package = shift;
418      # switch into foreign package and mixin plugin-module      # switch into foreign package and mixin plugin-module
419      my $self_classname = ref $self;      my $self_classname = ref $self;
420      eval("package $self_classname; use mixin '$package';");      eval("package $self_classname; use mixin '$package';");
421      #eval("use mixin_all '$package';");      #eval("use mixin_all '$package';");
422    
423        # FIXME: --- this is redundant ---
424      if ($@) {      if ($@) {
425        $meta->{loaded}->{$package} = 0;        $meta->{loaded}->{$package} = 0;
426        $logger->error( __PACKAGE__ . "->load: $@" );        $logger->error( __PACKAGE__ . "->load: $@" ) if $logger;
427      } else {      } else {
428        $meta->{loaded}->{$package} = 1;        $meta->{loaded}->{$package} = 1;
429      }      }
430        # FIXME: --- this is redundant ---
431    
432    }    }
433    
434    sub unload {    sub unload {
# Line 165  my $meta; Line 441  my $meta;
441      if ($meta->{loaded}->{$package}) {      if ($meta->{loaded}->{$package}) {
442        $meta->{loaded}->{$package} = 0;        $meta->{loaded}->{$package} = 0;
443        my $where = __PACKAGE__ . ':' . __LINE__;        my $where = __PACKAGE__ . ':' . __LINE__;
444        $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;
445      }      }
446    
447    }    }
# Line 180  my $meta; Line 456  my $meta;
456      my $self = shift;      my $self = shift;
457      my $includefile = shift;      my $includefile = shift;
458      my $package = shift;      my $package = shift;
459      # TODO: do better error-detection here / prevent dies under all circumstances!      
460      require $includefile;      # pre-flight checks
461        if (!$includefile) {
462          $self->raiseException('Filename for inclusion was empty.');
463          return;
464        }
465        
466        # go for it ...
467        eval("require '$includefile';");
468        # ... and handle errors afterwards catching every message from perl itself ...
469        return if $self->checkExceptions();
470        
471        # ... otherwise continue assuming everything is fine
472      $self->mixinPackage($package) if $package;      $self->mixinPackage($package) if $package;
473        
474    }    }
475    
476  1;  1;
477    __END__

Legend:
Removed from v.1.4  
changed lines
  Added in v.1.12

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