

Ruby Object Teams (ROT)
=======================
This package enables the ObjectTeams paradigm to the ruby language.
For detailed information and guide see www.objectteams.org .


Short Intro
===========
The ObjectTeams paradigm allows the programmer to encapsulate the
interaction of a set of objects (roles) into a compound object 
(the team). Aspects can be implemented as roles and are weaved into
domain classes via a connector at runtime (runtime weaving). 
These aspects can be explicitly activated and deactivated.


Definition of Ruby Object Teams 
===============================
A team definition is an outer class that must inherit from Team and
bundles a set of role-classes that are members of the team. 
Teams can be refined by inheritance. Each role-class is an usual
ruby class that encapsulates a specific state and behaviour.

  Example:

  class ObserverPattern < Team
    class Observer
      def update(observable)
        #code omitted
      end
    end
    class Observable
      attr :observer
      def add_observer(observer)
        #code omitted
      end
      def remove_observer(observer)
        #code omitted
      end
      def notify
        #code omitted
      end
    end
  end


  * Expected Methods
  ------------------
    To define methods, that have to be bound by the baseclass 
    (similar to abstract methods, that have to be implemented
     in a derived class) there is a new keyword: expected.
    Expected methods can be used in other methods, as were 
    implemented, but are bound by a connector to a base.

    Example:
    class Observer
      expected :update

      def test
        update()
      end
    end
  

  * Connector definition
  ----------------------
 
    a)Player definition
    
      A connector binds a defined team to a set of domain classes.
      This is done by a list of played_by clauses.

    b)Join-Point definition
      
      Join-points are existing methods of the domain class or new
      methods of the role-class that are accessible via the base class.
      There are several binding schemes:
        +before(rolemethod, basemethod)  invokes the specified 
              rolemethod each time before the basemethod is called.

        +after(rolemethod, basemethod)   invokes the specified 
              rolemethod each time after the basemethod is called.
              
        +replace(rolemethod, basemethod) invokes the specified
              rolemethod instead of the basemethod. (The basemethod
              is accessible in the rolemethod via base())

        +callin(rolemethod, basemethod)  register the specified
              rolemethod under a given name (basemethod). The
              basemethod must not exist.
     
     c)Expected method binding
       
       Expected methods must be bound by the baseclass. If the baseclass
       implements the requested action in a method with a different name,
       the role-call must delegated to the right basemethod. This is done
       by the delegate_to modifier:
        
        +delegate_to(rolemethod, basemethod) invokes the specified
              basemethod each time the specified rolemethod is called.
        

     Example:
     --------

     class ButtonObserver < ObserverPattern
       play_role(Observer, Window) {
         delegate_to("update", "updateWindow")
       }
       play_role(Observable, Button) {
         after("notify", "pressed")
       }
     end

     Means: -after Button.pressed is called, Observable.notify
             should be invoked
            -each call to Observer.update shall be delegated
             to Window.updateWindow



  * Connector activation/deactivation
  -----------------------------------
      The defined interaction of a connector must be activated/deactivated
      explicitely. There are two different ways to archieve this:


      Static Connector
      ----------------
        The simplest way to activate a connector is to choose a static connector. 
        Think of a static connector as a source code weaved connection, that 
        is always available without explicit activation.

        Example:
        Team.activate_static(ButtonObserver)
      

      Dynamic Connector
      -----------------
        The more advanced connector is a dynamic connector. A dynamic connector
        is an instance of a specific team and defines a context, in which the
        specific action is activated/deactivated.

        Example:
        observer = ButtonObserver.new()
        observer.while_active {
          #some action while the connector is active
        } 

        It is possible to have several instances of ButtonObserver (for example
        if you want to have different notification-channels).


  * Syntax
  --------

    class <MyTeam> < Team
      class <RoleClass>
      end
      <more roleclass definitions>
    end

    class <connector> < <MyTeam>
      play_role(<RoleClass>, <BaseClass>) {
          before(<RoleMethod>, <BaseMethod>)
          after(<RoleMethod>, <BaseMethod>)
          replace(<RoleMethod>, <BaseMethod>)
          delegate_to(<RoleMethod>, <BaseMethod>)
          <more callin/callout bindings>
      }
      <more play_role statements>
    end
      
    There are possibilities, to bind a rolemethod to a list of basemethods.
    The definition of such binding can be:
      -a list: [<basemethod>, <more basemethods>]
       eg: after("update", ["set_xpos", "set_ypos"])
      -a regular expression: /set.*/
       eg: after("update", /set.*/)
     

Example Code
============
The whole example discussed above is found in the sample/observer directory.



Limitation
==========

  -New keyword introduced:
     * expected
   Don't use this keyword in your code.
     
  -The callin method dispatching relies on ruby's method_missing feature.
   You can't use the method missing feature in base-classes.

  -Each roleclass gets new instance methods: 
     * base()
     * has_base?
     * get_connector()
   Be aware to implement this methods or use them in mistake.


Implementing Issues
===================

  Logger
  ------
  The objectteam uses a simple logger to log ROT-action. The logger is activated
  by the debug-option of ruby (enable with -d).
  The logger has adaptable parameters:
     -ActualLevel (the debug level [0=nothing to 5=everything])
     -MethodInfo (display method, which generates log-entry)
  and can have various Appender. Current implemented:
     -FileAppender
     -ConsoleAppender (default)
  Set appender with: Logger.set_appender(appender)

  StackTrace
  ----------
  If an exception is thrown and transported via call-bindings, the stack trace 
  is adapted, to hide the binding facilities. In most cases this is useful to
  see only domain specific trace. The trace remain unchanged, if the debug-option
  of ruby is enabled (-d).

  ot_assert
  ---------
  ROT evaluates a lot of assertions, by using ot_assert. If speed is an issue
  the asserts could be disabled.   


AUTHOR
======

Matthias Veit. April 2002.

email: Matthias Veit <matthias_veit@yahoo.de>


  
