docs: def soap(func=None, name=None, returns=None, args=None, doc=None, target='SOAP'):
      """
      soap supports multiple SOAP function collections, it'll save functions to 
      target dict, and you can give other target, but it should be keep up with
      SoapView.target definition.
      """
      global __soap_functions__
      
      returns = _fix_soap_kwargs(returns)
      args = _fix_soap_kwargs(args)
      
      if isinstance(func, str) and not name:
          return partial(soap, name=func, returns=returns, args=args, doc=doc, target=target)
      
      if not func:
          return partial(soap, name=name, returns=returns, args=args, doc=doc, target=target)
  
      target_functions = __soap_functions__.setdefault(target, {})
      if inspect.isfunction(func):
          f_name = func.__name__
          if name:
              f_name = name
          target_functions[f_name] = endpoint = ('.'.join([func.__module__, func.__name__]), returns, args, doc)
          func.soap_endpoint = (f_name, endpoint)
      elif inspect.isclass(func):
          if not name:
              name = func.__name__
          for _name in dir(func):
              f = getattr(func, _name)
              if (inspect.ismethod(f) or inspect.isfunction(f)) and not _name.startswith('_'):
                  f_name = name + '.' + f.__name__
                  endpoint = ('.'.join([func.__module__, func.__name__, _name]), returns, args, doc)
                  if hasattr(f, 'soap_endpoint'):
                      #the method has already been decorate by soap 
                      _n, _e = f.soap_endpoint
                      target_functions[name + '.' + _n] = endpoint
                      del target_functions[_n]
                  else:
                      target_functions[f_name] = endpoint
      else:
          raise Exception("Can't support this type [%r]" % func)
      return func