root/gaphor/branches/gaphor-0.12/doc/aspects-en.txt

Revision 241, 4.5 kB (checked in by arjanmol, 5 years ago)

*** empty log message ***

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 =======================================
2 Some explanations on the aspects module
3 =======================================
4
5
6 The main parts
7 --------------
8
9         - The **core** module defines the base class for all aspects.
10         - The **weaver** module defines the class which is responsible for
11           *weaving* code. The Weaver class is a Singleton, and you
12           can import the existing instance created in the *weaver* module, using
13           this import command : ::
14
15                  from logilab.aspects.weaver import weaver
16
17
18  
19           The main methods which can be called on the weaver's instance are
20           *weave_methods* and *unweave_methods* which weave and unweave some
21           aspect-related code on classes or instances.
22         - The *lib* module contains some useful aspects like :   
23                * **LoggerAspect** which will trace all method calls.
24                * **ContractAspect** which will enable design by contract in
25                  Python.
26                * Other aspects exist like **ProfilerAspect**, **DispatcherAspect**,
27                  **ConfirmationAspect** or **ObserverAspect**, but they are not
28                  always fully implemented. Anyway, you can use them or want to
29                  have a look at them to give you ideas of useful aspects or
30                  improvements.
31         - Some unit tests, and some examples can be found in the tests or examples
32           directory :
33           ::
34
35                 aspects/examples/contract_example.py
36                 aspects/examples/logger_example.py
37
38
39
40 A simple use case
41 -----------------
42
43 (Taken from logger_example.py) :
44 ::
45
46         # Import the weaver and the aspect to use
47         from logilab.aspects.weaver import weaver
48         from logilab.aspects.lib.logger import LoggerApsect
49         import sys
50        
51         stack = StackImpl()
52
53         # Push an element on the stack, the method call is not traced
54         stack.push("an element")
55
56         # Weave aspect code (log will be done on sys.stderr)
57         weaver.weave_methods(stack, LoggerAspect, sys.stderr)
58
59         # Push an other element, method call will now be traced
60         stack.push("another element")
61
62         # Unweave logger aspect
63         weaver.unweave(stack, LoggerAspect)
64
65         # Now, call methods aren't traced anymore
66         stack.push("a third element")
67
68
69 In this example, we have weaved an aspect on a given instance. As a
70 consequence, other instances of the same class will not be
71 aspected. The best way of weaving all class instances, is to weave the
72 aspect directly on the class, not on the instances. The syntax is
73 exactly the same : ::
74
75             weaver.weave_methods(StackImpl, LoggerAspect, sys.stderr)
76
77
78 Creating your own aspects
79 -------------------------
80
81 For now, it's only possible to wrap methods, not attribute accesses.
82
83 To create a new aspect, you must define a class which inherits from
84 *AbstractAspect* (in *aspects.core*), and define *before()*, *after()* and
85 *around()* methods. Note that you can choose to override only one of this
86 three methods since the default behaviour is to "simply pass". It is
87 **important**, when overriding the *around* method to explicitly call
88 *self._proceed(...)* which is the effective call to the wrapped method.
89
90
91 Let's write a simple aspect which will write **BEFORE** before the method
92 call and **AFTER** after.
93
94 ::
95
96     from logilab.aspects.core import AbstractAspect
97     from logilab.aspects.prototypes import reassign_function_arguments
98
99
100     class SimpleAspect(AbstractAspect):
101    
102         def before(self, wobj, *args, **kwargs):
103             """Before method
104             """
105             print "BEFORE ",self.method_name
106            
107
108         def after(self, wobj, ret_v, exec_excpt, *args, **kwargs):
109             """After method.
110             print the return value
111             """
112             print "AFTER ",self.method_name,", return value is ", ret_v
113
114
115 This example is quite simple, and is not really useful, but it should
116 show how to define your own aspects.
117
118 Here is some information on the above code:
119
120          - The *before()* parameters are :
121          
122                * *self* : The aspect instance
123                * *wobj* : The weaved object instance (on which is called
124                  the wrapped method)
125                * *args* and *kwargs* are the arguments passed to the wrapped method.
126                  If inside *before()*, you want to have the name and the value of
127                  each argument, you can use the function *reassign_function_arguments*
128                  in the *aspects.prototypes* module. It will return a dictionnary
129                  containing arg names as keys, and arg values as values.
130          - The *after()* parameters are the same, with two more arguments :
131
132                * *ret_v* which is the value returned by the wrapped method.
133                * *exec_excpt* which is the exception raised by the wrapped method,
134                  or None if no exception was raised.
135
136
137
138 **IMPORTANT** : for now, each aspect instance is attached to a specific
139 method, this will very soon change because it is not handy, and quite
140 expensive.
141
Note: See TracBrowser for help on using the browser.