# HG changeset patch
# User Jason Grout <jason-sage@creativetrax.com>
# Date 1268272078 21600
# Node ID 64b035839e6283e4a81895a210fd3f0d80a87027
# Parent  e9c9eff84491dffdfa1e75de517a9e46fa40636a
Make a sage_wraps decorator, reorganize the interact library, and add a calculus example.

diff -r e9c9eff84491 -r 64b035839e62 sage/interacts/__init__.py
--- a/sage/interacts/__init__.py	Wed Mar 10 05:20:22 2010 -0800
+++ b/sage/interacts/__init__.py	Wed Mar 10 19:47:58 2010 -0600
@@ -1,5 +1,5 @@
 """
 Interacts included with sage 
 """
-
-from decorator import library_interact, demo
+import calculus
+import library
diff -r e9c9eff84491 -r 64b035839e62 sage/interacts/calculus.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sage/interacts/calculus.py	Wed Mar 10 19:47:58 2010 -0600
@@ -0,0 +1,1 @@
+from library import taylor_polynomial
diff -r e9c9eff84491 -r 64b035839e62 sage/interacts/decorator.py
--- a/sage/interacts/decorator.py	Wed Mar 10 05:20:22 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-"""
-A decorator to enable interacts in the Sage library.
-"""
-
-from sagenb.notebook.interact import interact, slider, range_slider
-from sage.misc.html import html
-
-def library_interact(f):
-    """
-    This is a decorator for using interacts in the Sage library.
-
-    EXAMPLES::
-
-        sage: @interacts.library_interact
-        ... def f(n=5): print n
-        ...   
-        sage: f()  # an interact appears
-        <html>...</html>
-    """
-    def new_fun():
-       # Maybe program around bug (?) in the notebook:
-       html("</pre>")
-       # This prints out the relevant html code to make
-       # the interact appear:
-       interact(f)
-    # preserve the docstring
-    new_fun.__doc__ = f.__doc__ 
-    return new_fun
-
-@library_interact
-def demo(n=tuple(range(10)), m=tuple(range(10))):
-    """
-    This is a demo interact that sums two numbers.
-    
-    INPUT:
-        
-        - `n` -- integer slider
-        - `m` -- integer slider
-
-    EXAMPLES::
-      
-        sage: interacts.demo()
-        <html>...</html>
-    """
-    print n+m
diff -r e9c9eff84491 -r 64b035839e62 sage/interacts/library.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sage/interacts/library.py	Wed Mar 10 19:47:58 2010 -0600
@@ -0,0 +1,73 @@
+"""
+A library of interacts
+"""
+
+from sagenb.notebook.interact import interact, slider, range_slider, input_box
+from sage.all import sin, plot, point, html, show, latex, SR,exp
+x=SR.var('x')
+
+from sage.misc.misc import sage_wraps
+from sage.misc.html import html
+
+def library_interact(f):
+    """
+    This is a decorator for using interacts in the Sage library.
+
+    EXAMPLES::
+
+        sage: @interacts.decorator.library_interact
+        ... def f(n=5): print n
+        ...   
+        sage: f()  # an interact appears
+        <html>...</html>
+    """
+    @sage_wraps(f)
+    def library_wrapper():
+       # Maybe program around bug (?) in the notebook:
+       html("</pre>")
+       # This prints out the relevant html code to make
+       # the interact appear:
+       interact(f)
+    return library_wrapper
+
+@library_interact
+def demo(n=tuple(range(10)), m=tuple(range(10))):
+    """
+    This is a demo interact that sums two numbers.
+    
+    INPUT:
+        
+        - `n` -- integer slider
+        - `m` -- integer slider
+
+    EXAMPLES::
+      
+        sage: interacts.decorator.demo()
+        <html>...</html>
+    """
+    print n+m
+
+
+
+@library_interact
+def taylor_polynomial(f=input_box(sin(x)*exp(-x)), order=slider(range(1,13))):
+    """
+    An interact which illustrates the Taylor polynomial approximation
+    of various orders around `x=0`.
+
+        - `f` -- function expression
+        - ``order`` -- integer slider
+
+    EXAMPLES::
+      
+        sage: interacts.calculus.taylor_polynomial()
+        <html>...</html>
+    """
+    x0  = 0
+    p   = plot(f,(x,-1,5), thickness=2)
+    dot = point((x0,f(x=x0)),pointsize=80,rgbcolor=(1,0,0))
+    ft = f.taylor(x,x0,order)
+    pt = plot(ft,(-1, 5), color='green', thickness=2)
+    html('$f(x)\;=\;%s$'%latex(f))
+    html('$\hat{f}(x;%s)\;=\;%s+\mathcal{O}(x^{%s})$'%(x0,latex(ft),order+1))
+    show(dot + p + pt, ymin = -.5, ymax = 1)
diff -r e9c9eff84491 -r 64b035839e62 sage/misc/misc.py
--- a/sage/misc/misc.py	Wed Mar 10 05:20:22 2010 -0800
+++ b/sage/misc/misc.py	Wed Mar 10 19:47:58 2010 -0600
@@ -2333,3 +2333,40 @@
         inject_variable(name, value)
     else:
         inject_variable_test(name, value, depth - 1)
+
+from functools import update_wrapper, WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES
+from sage.misc.sageinspect import sage_getsource
+
+def sage_wraps(wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES):
+    """
+    Decorator factory to apply update_wrapper() to a wrapper function,
+    and additionally add a _sage_src_ attribute for Sage introspection.
+
+    Use this exactly like @wraps from the functools module.
+
+    EXAMPLES::
+
+        sage: from sage.misc.misc import sage_wraps
+        sage: def square(f):
+        ...     @sage_wraps(f)
+        ...     def new_f(x):
+        ...         return f(x)*f(x)
+        ...     return new_f
+        sage: @square
+        ... def g(x):
+        ...     "My little function"
+        ...     return x
+        sage: g(2)
+        4
+        sage: g(x)
+        x^2
+        sage: g._sage_src_()
+        '@square...def g(x)...'
+        sage: g.__doc__
+        'My little function'
+    """
+    def f(wrapper):
+        update_wrapper(wrapper, wrapped, assigned=assigned, updated=updated)
+        wrapper._sage_src_=lambda: sage_getsource(wrapped)
+        return wrapper
+    return f
