===========================================
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_methods* et *unweave_methods* qui tissent ou dtissent
	  le code li  un aspect sur des classes ou des instances.
	- 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



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 que de dfinir 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
    from logilab.aspects.prototypes import reassign_function_arguments


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

	def after(self, wobj, ret_v, exec_excpt, *args, **kwargs):
	    """After method.
	    print the return value
	    """
	    print "AFTER ",self.method_name,", return value is ", 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.
	       * *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()* sont les mmes, avec en plus :

	       * *ret_v* qui reprsente la valeur de retour de la mthode
	         wrappe.
	       * *exec_excpt* 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.


**IMPORTANT** : pour l'instant, chaque instance d'aspect est rattache 
une unique mthode. Cela va rapidement changer puisque ce n'est pas trs
pratique, et que c'est trs coteux.

