import sys
sys.dont_write_bytecode = True
from copyleft import *

"""
This file address three problems:

- The demo problem: how to show off your cool code.
- The test suite problem: how to check if past
  code still runs.
- The command-line problem: how to call code from
  command-line.

####################################################
Quick and dirty method. We do better below. 
"""

def go(f):
  "Annotate functions to run at load time."
  print "\n# ---|", f.__name__,"|-----------------"
  if f.__doc__:
    print "#", f.__doc__
  f()
  return f

#@go #<-- uncomment this line and load this file
def someFunctionWithLongName():
  "example of using @go."
  print "All done with a few keystrokes"
  quit()

"""#################################################
PROBLEM: How to show off you cool code to other
people, remembering all those tricks that make the
code do cool things.

SOLUTION: Do all those cool things in a function.

CONVENTIONS :  
1. Annotate those functions with @demo 
2. Demo functions end in "d".  
3. If there are many 
   demos, make a seperate file, also ending in "d". 
   So demos for lib.py would be found in libd.py.
3. For functions that random numbers, there is no
   call to "resetSeed" unless that the argument to
   that call can be set by a demo function.
"""

def demo0(f=None): return demo(f,0)
def demo1(f=None): return demo(f,1)
def demo2(f=None): return demo(f,2)
def demo3(f=None): return demo(f,3)
def demo4(f=None): return demo(f,4)
def demo5(f=None): return demo(f,5)
def demo6(f=None): return demo(f,6)
def demo7(f=None): return demo(f,7)

def demo(f=None,lvl=0,d={}):
  """
  A decorator for a demo suite. E.g.

    @demo1
    def demoed() : 
      "Doco about this demo"
      print "I am a demo"
  
  will add demoed to a list of known demos. 
  Then, we can call all demos using "demo()".
  Note that demos can be defined at one of
  eight levels demo0...demo7 and higher
  level demos are run after lower-ones. 
  """
  if f: 
    if not lvl in d: d[lvl] = []
    d[lvl]  += [f]
    return f
  for lvl in sorted(d.keys()):
    for f in d[lvl]: 
      print '\n--|','('+str(lvl)+')',\
           f.func_name,'|','-'*40,'\n',f.__doc__,'\n'
      f()

"""#################################################
PROBLEM: How to build a regression suite so that
tomorrow you can test that the code still does what
it did yesterday?

SOLUTION: Write lots of functions that return 
(want,got) pairs, count how many times want == got 
and want != got.

CONVENTIONS:
1. Annotate those functions with @test
2. Test functions end in "d". 
3. If lots of tests, store them in a seperate demos 
   files (name ending in "d"). 
"""

def test(f=None,tests=[]): 
  """ 
  A decorator for test suites. Each test function 
  returns a list of n pairs `[(got1,want1),(got2,want2),...]` 
  and this scores n more "passes" if  `got==want`. E.g.

    @test
    def tested(): 
      thing = 22
      return [(22,thing),  
              (False, type thing = float)]
    
  will add "tested" to a list of known tests. Then,
  we can call all tests and get a print out of 
  number of passes and fails using "test()
  """
  if f: tests.append(f); return f
  ok=no=0
  for t in tests: 
    print "#",t.func_name + ': ',t.__doc__
    for n,(want,got) in  enumerate(t()):
      if want == got:
        ok += 1; print "CORRECT:",t.func_name,'question', n+1
      else:
        no += 1; print "WRONG  :",t.func_name,'question',n+1
  if tests:
    print '\n# Final score = %s/%s = %s%% CORRECT' \
            % (ok,(ok+no),round(100*ok/(ok+no)))

"""#################################################
PROBLEM: How to call all these code/test functions
from the command line (handling arguments, compiling
number strings, etc).

SOLUTION: See below.

CONVENTIONS: The function called in this way has 
default values to its arguments, which can be 
over-ridden from the command line.
"""

def cmd(com='demo()'):
  """
  If the call to python file.py includes additional;
  arguments then parse them into a function call.
  If not, call some default command. For example,
  if this line is added to end of file:

   if __name__ == '__main__' : 
        eval(cmd('copyleft()'))

  Then if the call this file as follows:

    python demo,py 

  then some default copyright notice will be shown.
  But it we do it again using

    python demo.py copyleft hilary 2016 1000

  then we see a customized copyright notice where
  the defaults for the copyleft function have been
  replaced with name=hilary, year=2016, rate=1000.
  """
  if len(sys.argv) < 2:
    return com
  else: 
    def stringp(x): 
      return isinstance(x,basestring)
    def atom(x):
      try: return float(x)
      except ValueError: return x
    def wrapper(x):
        return "'" + x + "'" if stringp(x) else str(x)
    words = map(wrapper,map(atom,sys.argv[2:]))
    return sys.argv[1] + '(' + ','.join(words) + ')'

if __name__ == '__main__' : 
  eval(cmd('copyleft()'))
