Merge branch 'feature-list_defs' of https://bitbucket.org/jvanasco/mako into pr16
diff --git a/mako/template.py b/mako/template.py
index afb679a..8fd6062 100644
--- a/mako/template.py
+++ b/mako/template.py
@@ -475,6 +475,10 @@
 
         return DefTemplate(self, getattr(self.module, "render_%s" % name))
 
+    def list_defs(self):
+        """returns a list of defs in the template"""
+        return [i[7:] for i in dir(self.module) if i[:7] == 'render_']
+        
     def _get_def_callable(self, name):
         return getattr(self.module, "render_%s" % name)
 
diff --git a/test/test_def.py b/test/test_def.py
index 8b32561..19142c8 100644
--- a/test/test_def.py
+++ b/test/test_def.py
@@ -123,6 +123,41 @@
                         filters=flatten_result,
                         template_args={'q': 5, 'zq': 'test'})
 
+    def test_def_operations(self):
+        """test get/list/has def"""
+
+        template = Template("""
+
+            this is the body
+
+            <%def name="a()">
+                this is a
+            </%def>
+
+            <%def name="b(x, y)">
+                this is b, ${x} ${y}
+            </%def>
+
+        """)
+
+        assert template.get_def("a")
+        assert template.get_def("b")
+        assert_raises(AttributeError,
+                      template.get_def,
+                      ("c")
+                      )
+
+        assert template.has_def("a")
+        assert template.has_def("b")
+        assert not template.has_def("c")
+
+        defs = template.list_defs()
+        assert "a" in defs
+        assert "b" in defs
+        assert "body" in defs
+        assert "c" not in defs
+
+
 class ScopeTest(TemplateTest):
     """test scoping rules.  The key is, enclosing
     scope always takes precedence over contextual scope."""