===========================================
Quelques explications sur le module aspects
===========================================


Les principales parties
-----------------------

- le module **core** dfinit la classe de base des Aspects.
- le module **weaver** dfinit la classe charge du *tissage*. Une seule
  instance du tisseur doit tre cre dans tout le programme si on veut
  pouvoir l'utiliser correctement. Cette instance est cre dans ce
  module et on l'obtient par ::

	 from logilab.aspects.wevaer import weaver

  Les principales oprations que l'on peut effectuer avec le tisseur
  sont *weave_pointcut* et *unweave_pointcut* qui tissent ou dtissent
  le code li  un aspect sur un ensemble de points d'arrts. Il existe
  galement des mthodes qui simplifient le tissage d'un aspect dans
  l'ensemble d'un module ou l'ensemble d'une classe / instance.	  
- Le module *lib* contient l'ensemble des aspects de
  base que l'on peut souhaiter utiliser. Pour le moment, il en existe
  deux :
  
       * **LoggerAspect** qui va tracer l'ensemble des appels de mthodes ;
       * **ContractAspect** qui permet l'utilisation de contrats en Python.
       * Il existe d'autres aspects comme **ProfilerAspect**, **DispatcherAspect**,
         **ConfirmationAspect** ou **ObserverAspect**, mais ils sont en
	 cours de dveloppement et ils ne sont ici que pour donner des
	 ides de ce qu'il est possible de faire avec les aspects ou
	 des ides d'amliorations.
- Enfin, il y a un module de tests unitaires, ainsi que des exemples
  d'utilisation des aspects prcits dans le rpertoire *examples*.
  Par exemple, les exemples des *contrats* et du *logger* se trouvent ici :
  ::

	aspects/examples/contract_example.py
	aspects/examples/logger_example.py



Comment dfinir un point d'arrt
--------------------------------

Lorsque vous souhaitez tisser un aspect sur une classe entire, ou sur un module
entier, vous pouvez directement utiliser les mthode *weave_methods* ou
*weave_module*. Mais lorsque vous souhaitez tisser un aspect seulement sur
une partie de la classe (c.a.d pas sur l'ensemble de ses mthodes), alors
vous devrez crer une instance de classe *PointCut*, puis appeler la
mthode *weave_pointcut*.

Un point d'arrt, dans ce paquet, est tout simplement un dictionnaire avec
pour cls, des instances ou des classes, et pour valeurs, des listes de mthodes
sur lesquelles vous souhaitez appliquer l'aspect.
La classe *PointCut* drivant du type dictionnaire , il est possible de dfinir
directement ses cls et ses valeurs, mais il est cependant conseill d'utiliser
les mthodes existantes :

- **add_method** (resp. **remove_method**) qui va ajouter (resp. retirer) une
  mthode, relative  une classe ou instance donne, dans le Pointcut

- la liste des mthodes statiques de la classe *PointCut* qui permettent
  d'instantier directement un objet *PointCut*  partir d'une classe,
  d'une instance, ou d'un module :

   + **create_pointcut_from_module()**
   
   + **create_pointcut_from_class()**

Quand l'objet est cr, pour tisser l'aspect, il suffit de faire : ::

      weaver.weave_pointcut(pointcut, aspect_class)


	
Un exemple d'utilisation
------------------------

(Extrait de logger_example.py) :

::

	# On importe le tisseur et l'aspect qu'on souhaite utiliser
	from logilab.aspects.weaver import weaver
	from logilab.aspects.lib.logger import LoggerApsect
	import sys
	
	stack = StackImpl()

	# Ajoutons un lment  la pile, l'appel n'est pas trac
	stack.push("an element")

	# on applique l'aspect (on spcifie que le traage se fera
	# sur la sortie standard d'erreur)
	weaver.weave_methods(stack, LoggerAspect, sys.stderr)

	# Rajoutons un autre lment. Maintenant, l'appel sera trac
	stack.push("another element")

	# On enlve l'aspect Logger
	weaver.unweave(stack, LoggerAspect)

	# Maintenant, les appels ne sont plus tracs
	stack.push("a third element")


Dans cette exemple, on a appliqu un aspect un une instance donne. Par
consquent, les autres instances de la mme classe ne seront pas aspectes.
Si on avait voulu faire en sorte que toutes les instances d'une classe soient
aspectes, il aurait alors fallu tisser l'aspect non pas sur l'instance, mais
directement sur la classe. La syntaxe est la mme ::

	    weaver.weave_methods(StackImpl, LoggerAspect, sys.stderr)


Comment crer son aspect:
-------------------------

Pour l'instant, il n'est possible de dfinir que ce qui va tre excut
avant et aprs des appels de mthodes. Il sera rapidement possible de dfinir
le mme genre de comportement pour la modification d'attributs.

Pour crer un nouvel aspect, il faut crer une classe qui hrite de
*AbstractAspect* (dans *aspects.core*), et dfinir les mthodes *before()*
et *after()* et *around()*. Il est tout  fait possible de ne surcharger
qu'une seule de ces trois mthodes pusique le comportement par dfaut
est *simplement de passer*. Il est **important**, lorsque l'on surcharge
la mthode *around* de faire appel dedans  la mthode *self._proceed* qui
correspond  l'appel de la mthode wrappe.

Ecrivons un aspect simple qui ne fait que crire **BEFORE** avant que
la mthode ne soit effectivement appele et **AFTER** aprs.

::

    from logilab.aspects.core import AbstractAspect

    class SimpleAspect(AbstractAspect):
    
	def before(self, wobj, context, *args, **kwargs):
	    """Before method
	    """
	    print "BEFORE ",context['method_name']
	    

	def after(self, wobj, context, *args, **kwargs):
	    """After method.
	    print the return value
	    """
	    print "AFTER ",self.method_name,", return value is ", context['ret_v']


Cet exemple est trs simple et n'a pas vraiment d'utilit, mais il permet
de voir comment doit tre cr un aspect.
Quelques prcisions sur le code ci-dessus:

- les paramtres de *before()* sont :

      * *self* : l'instance de l'aspect
      
      * *wobj* : l'instance de l'objet tiss, c'est  dire l'objet
        sur lequel est appele la mthode qu'on a wrappe.
	
      * context : un dictionnaire qui contient un ensemble de valeurs
        relatives  l'excution de la mthode. (cf. ci-dessous)
	
      * *args* et *kwargs* sont les arguments passs  la mthode
	 wrappe. Si l'on souhaite avoir le nom exact des arguments
	 ainsi que leur valeur au moment de l'appel, il existe une
	 fonction dans le module *aspects/prototypes* (*reassign_function_arguments*)
	 qui renvoie un dictionnaire avec le nom des paramtres en "cls", et
	 leur valeur au moment de l'appel en "valeurs".
- les paramtres de *after()*  et de *around()* sont les mmes que
  pour *before*

- *context* possde les cls suivantes :
      * *method_name* qui reprsente le nom de la mthode appele.
        (disponible dans *before()*, *around()*, et *after()*)
	
      * *ret_v* qui reprsente la valeur de retour de la mthode
        wrappe.
        (disponible dans *after()*)
	
      * *excption* qui reprsente l'exception leve par la mthode
        wrappe pendant son excution. Si la mthode n'a lev aucune
	exception, alors *exec_excpt* vaut None.
	(disponible dans *after()*)


**IMPORTANT** : le tisseur (classe *Weaver*) est un Singleton qui garde  tout
moment l'ensemble des informations relatives aux mthodes tisses, c'est--dire
quelle mthode a t tisse avec quel aspect, etc.. Lorsque l'on tisse
un aspect sur une mthode, le tisseur regardera si cet aspect a dj t tisser,
et, dans ce cas, utilisera l'instance dj existante de cet aspect. Cela
va rapidement changer  cause des contraintes que cela induit.

Exemples des aspects fournis avec le module
-------------------------------------------

Le module *aspects* contient des aspects utiles comme :

* **LoggerAspect** : pour journaliser l'ensemble des appels de mthodes

* **ContractAspect** : les contrats peuvent tre vus comme une sous-partie des
  aspects. Cet aspect va permettre de faire de la programmation par contrats.
  Nous avons choisi de considrer les dfinitions de contrats comme partie
  intgrante de la documenation. Les conditions sont donc spcifies dans
  les chanes de documentation des mthodes, et des modules. Vous pourrez
  trouver plus d'informations sur les contrats et les aspects ici_.

* Il y a galement d'autres aspects comme **ProfilerAspect** (un simple
  profiler de mthodes), **DispatcherAspect** (pour permettre l'utilisation
  de multimthodes), **ConfirmationAspect** (pour demander confirmation avant
  une opration), ou bien **ObserverAspect** (une implmentation en aspects
  du patron de conception Observer), mais ils ne sont pas toujours compltement
  implments. Quoiqu'il en soit, vous pouvez toujours les utiliser pour
  vous donner des ides d'aspects utiles ou pour d'amliorations.

Plus d'informations  propos de l'AOP
-------------------------------------

Voici un ensemble de liens utiles pour la **Programmation oriente Aspect**:

* `L'ide originale`_.

* `Le portail officiel pour les aspects`_.

* Une autre `page pleine de liens sur les aspects`_.

* AspectJ est une implmentation complte de l'AOP. Voici un `tutorial`_.

* `Quelques rsultats`_ du moteur de recherche de citations de NEC.

* D'autres solutions en Python pour l'AOP : Pythius_, et PEAK_ (qui n'est en ralit pas uniquement une implmentation pour les aspects)


Tlchargement
--------------

Le module *aspects* peut tre tlcharg  partir du `site FTP de Logilab`_.
Vous y trouverez une archive contenant les sources du module ainsi que
des paquets debian. Pour l'installer  partir des sources, il suffit de
taper : **python setup.py install** aprs avoir dcompress l'archive.


Vos commentaires
----------------

N'hsitez pas  nous faire de tout commentaire, patch, ou question sur
la liste de diffusion `python-projects`_.

.. _ici: contracts-fr.html
.. _`L'ide originale`: http://www.parc.xerox.com/csl/groups/sda/publications/papers/Kiczales-ECOOP97/for-web.pdf
.. _`Le portail officiel pour les aspects`: http://www.aosd.net
.. _`page pleine de liens sur les aspects`: http://www.volantec.biz/aspect.htm
.. _`tutorial`: http://www.eclipse.org/aspectj/
.. _`Quelques rsultats`: http://citeseer.nj.nec.com/highley99aspect.html
.. _Pythius: http://pythius.sourceforge.net/
.. _PEAK: http://peak.telecommunity.com/Articles/WhatisPEAK.html
.. _`site FTP de Logilab`: ftp://ftp.logilab.org/pub/aspects
.. _`python-projects`: http://lists.logilab.org/mailman/listinfo/python-projects
