summaryrefslogtreecommitdiff
path: root/pypers/pro.txt
blob: b71158f7c9068bb079a68aaad57bc245489e79fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
Operator overloading is best done with metaclasses:

 ::

  #<autowrap.py>

  import inspect

  class wrappedmethod(Customizable):
      """Customizable method factory intended for derivation.
      The wrapper method is overridden in the children."""

      logfile=sys.stdout # default
      namespace='' # default

      def __new__(cls,meth): # meth is a descriptor
          if isinstance(meth,FunctionType):
              kind=0 # regular method
              func=meth
          elif isinstance(meth,staticmethod):
              kind=1 # static method
              func=meth.__get__('whatever')
          elif isinstance(meth,classmethod):
              kind=2 # class method
              func=meth.__get__('whatever','whatever').im_func 
          elif isinstance(meth,wrappedmethod): # already wrapped
              return meth # do nothing
          elif inspect.ismethoddescriptor(meth):
              kind=0; func=meth # for many builtin methods 
          else:
              return meth # do nothing
          self=super(wrappedmethod,cls).__new__(cls)
          self.kind=kind; self.func=func # pre-initialize
          return self

      def __init__(self,meth): # meth not used
          self.logfile=self.logfile # default values
          self.namespace=self.namespace # copy the current

      def __get__(self,obj,cls): # closure 
          def _(*args,**kw):
              if obj is None: o=() # unbound method call
              else: o=(obj,) # bound method call
              allargs=[o,(),(cls,)][self.kind]+args 
              return self.wrapper()(*allargs,**kw)
          return _ # the wrapped function
          # allargs is the only nontrivial line in _; it adds
          # 0 - obj if meth is a regular method
          # 1 - nothing if meth is a static method
          # 2 - cls if meth is a class method

      def wrapper(self): return self.func # do nothing, to be overridden
  
  class autowrappedmethod(wrappedmethod):
      """Makes the method returning cls instances, by wrapping its
      output with cls"""
      klass=None # has to be fixed dynamically from outside
      def __init__(self,meth):
          super(autowrappedmethod,self).__init__(meth) # cooperative
          self.klass=self.klass # class variable -> instance variable
      def wrapper(self): # closure
          return lambda *args,**kw: self.klass(self.func(*args,**kw))

  class AutoWrapped(type):
      """Metaclass that looks at the methods declared in the attributes 
      builtinlist and wraplist of its instances and wraps them with
      autowrappedmethod."""
      def __init__(cls,name,bases,dic):
          super(AutoWrapped,cls).__init__(name,bases,dic) # cooperative
          cls.builtinlist=getattr(cls,'builtinlist',[])
          if not hasattr(cls,'diclist') : # true only at the first call
              cls.diclist=[(a,vars(bases[0])[a]) for a in cls.builtinlist]
          if dic.has_key('wraplist'): # can be true at any call
              cls.diclist+=[(a,dic[a]) for a in cls.wraplist] 
          wrapper=autowrappedmethod.With(klass=cls)
          d=dict([(a,wrapper(v)) for a,v in cls.diclist])
          customize(cls,**d)
    
  class Str(str):
      __metaclass__=AutoWrapped
      builtinlist="""__add__ __mod__ __mul__ __rmod__ __rmul__ capitalize
          center expandtabs join ljust lower lstrip replace rjust rstrip strip
          swapcase title translate upper zfill""".split()

  #</autowrap.py>
 
Here I show various tests.

  .. doctest

  >>> from autowrap import Str
  >>> sum=Str('a')+Str('b') # check the sum
  >>> print sum, type(sum)
  ab <class 'autowrap.Str'>
  >>> rprod=Str('a')*2 # check the right product 
  >>> print rprod,type(rprod)
  aa <class 'autowrap.Str'>
  >>> lprod=2*Str('a') # check the left product 
  >>> print lprod,type(lprod)
  aa <class 'autowrap.Str'>
  >>> r=Str('a').replace('a','b') # check replace
  >>> print r,type(r)
  b <class 'autowrap.Str'>
  >>> r=Str('a').capitalize() # check capitalize
  >>> print r,type(r)
  A <class 'autowrap.Str'>