# Arithmetic Example with Prefix Debug Decorator Using Defaults
# Python 3 Reflexive Metaprogramming
# H. Conrad Cunningham

# Developed for CSci 658, Software Language Engineering, Spring 2018

#234567890123456789012345678901234567890123456789012345678901234567890

# 2018-03-24: (V1) debug adapted from Beazley's 2013 Metaprogramming
#             tutorial

from functools import wraps, partial

def debug(func=None, *, prefix=''):
    '''
    Decorator with or without optional arguments
    '''
    print(str(func))
    if func is None:
        return partial(debug, prefix=prefix)
    
    msg = prefix + func.__qualname__
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(msg)
        return func(*args, **kwargs)
    return wrapper

@debug(prefix='***')
def add(x,y):
    'Add x and y'
    return x+y

@debug(prefix='@@@') 
def sub(x, y):
    'Subtract y from x'
    return x - y

@debug(prefix='***') 
def mul(x, y):
    'Multiply x and y'
    return x * y

@debug
def div(x, y):
    'Divide x by y'
    return x / y

if __name__ == '__main__':
    print(f'add(2,5) = {add(2,5)}')
    print(f'add.__qualname__ = {add.__qualname__}')
    print(f'add.__doc__ = {add.__doc__}')
    print(f'add(2,5) = {add(2,5)}')
    print(f'sub(2,5) = {sub(2,5)}')
    print(f'mul(2,5) = {mul(2,5)}')
    print(f'div(2,5) = {div(2,5)}')
    
        
