Author: ianb
Date: 2008-04-23 00:55:04 -0600 (Wed, 23 Apr 2008)
New Revision: 3395

Added:
   FormEncode/trunk/formencode/htmlrename.py
   FormEncode/trunk/formencode/rewritingparser.py
   FormEncode/trunk/tests/test_htmlrename.py
Modified:
   FormEncode/trunk/docs/news.txt
   FormEncode/trunk/formencode/htmlfill.py
Log:
Added htmlrename, which renames input field names

Modified: FormEncode/trunk/docs/news.txt
===================================================================
--- FormEncode/trunk/docs/news.txt      2008-04-23 06:53:03 UTC (rev 3394)
+++ FormEncode/trunk/docs/news.txt      2008-04-23 06:55:04 UTC (rev 3395)
@@ -13,6 +13,8 @@
 * Remove deprecated modules: ``fields``, ``formgen``, ``htmlform``,
   ``sqlformgen``, and ``sqlschema``.
 
+* Added ``formencode.htmlrename``, which renames HTML inputs.
+
 1.0.1
 -----
 

Modified: FormEncode/trunk/formencode/htmlfill.py
===================================================================
--- FormEncode/trunk/formencode/htmlfill.py     2008-04-23 06:53:03 UTC (rev 
3394)
+++ FormEncode/trunk/formencode/htmlfill.py     2008-04-23 06:55:04 UTC (rev 
3395)
@@ -4,9 +4,8 @@
 """
 
 import HTMLParser
-import cgi
 import re
-from htmlentitydefs import name2codepoint
+from formencode.rewritingparser import RewritingParser, html_quote
 
 __all__ = ['render', 'htmlliteral', 'default_formatter',
            'none_formatter', 'escape_formatter',
@@ -102,17 +101,6 @@
     def __html__(self):
         return self.html
 
-def html_quote(v):
-    if v is None:
-        return ''
-    elif hasattr(v, '__html__'):
-        return v.__html__()
-    elif isinstance(v, basestring):
-        return cgi.escape(v, 1)
-    else:
-        # @@: Should this be unicode(v) or str(v)?
-        return cgi.escape(str(v), 1)
-
 def default_formatter(error):
     """
     Formatter that escapes the error, wraps the error in a span with
@@ -140,7 +128,7 @@
     error = error.replace('\n', '<br>\n')
     return error
 
-class FillingParser(HTMLParser.HTMLParser):
+class FillingParser(RewritingParser):
     r"""
     Fills HTML with default values, as in a form.
 
@@ -177,8 +165,7 @@
                  add_attributes=None, listener=None,
                  auto_error_formatter=None,
                  text_as_default=False, encoding=None, prefix_error=True):
-        HTMLParser.HTMLParser.__init__(self)
-        self._content = []
+        RewritingParser.__init__(self)
         self.source = None
         self.lines = None
         self.source_pos = None
@@ -207,18 +194,9 @@
         self.encoding = encoding
         self.prefix_error = prefix_error
 
-    def feed(self, data):
-        self.data_is_str = isinstance(data, str)
-        self.source = data
-        self.lines = data.split('\n')
-        self.source_pos = 1, 0
-        if self.listener:
-            self.listener.reset()
-        HTMLParser.HTMLParser.feed(self, data)
-
     def close(self):
         self.handle_misc(None)
-        HTMLParser.HTMLParser.close(self)
+        RewritingParser.close(self)
         unused_errors = self.errors.copy()
         for key in self.used_errors.keys():
             if unused_errors.has_key(key):
@@ -252,50 +230,14 @@
                     item = item.decode(self.encoding)
                 new_content.append(item)
             self._content = new_content
-        try:
-            self._text = ''.join([
-                t for t in self._content if not isinstance(t, tuple)])
-        except UnicodeDecodeError, e:
-            if self.data_is_str:
-                e.reason += (
-                    " the form was passed in as an encoded string, but "
-                    "some data or error messages were unicode strings; "
-                    "the form should be passed in as a unicode string")
-            else:
-                e.reason += (
-                    " the form was passed in as an unicode string, but "
-                    "some data or error message was an encoded string; "
-                    "the data and error messages should be passed in as "
-                    "unicode strings")
-            raise
+        self._text = self._get_text()
 
+    def skip_output(self):
+        return self.in_textarea or self.skip_error
+
     def add_key(self, key):
         self.used_keys[key] = 1
 
-    _entityref_re = re.compile('&([a-zA-Z][-.a-zA-Z\d]*);')
-    _charref_re = re.compile('&#(\d+|[xX][a-fA-F\d]+);')
-
-    def unescape(self, s):
-        s = self._entityref_re.sub(self._sub_entityref, s)
-        s = self._charref_re.sub(self._sub_charref, s)
-        return s
-
-    def _sub_entityref(self, match):
-        name = match.group(1)
-        if name not in name2codepoint:
-            # If we don't recognize it, pass it through as though it
-            # wasn't an entity ref at all
-            return match.group(0)
-        return unichr(name2codepoint[name])
-
-    def _sub_charref(self, match):
-        num = match.group(1)
-        if num.lower().startswith('x'):
-            num = int(num[1:], 16)
-        else:
-            num = int(num)
-        return unichr(num)
-
     def handle_starttag(self, tag, attrs, startend=False):
         self.write_pos()
         if tag == 'input':
@@ -318,16 +260,6 @@
         if self.listener:
             self.listener.listen_input(self, tag, attrs)
 
-    def handle_misc(self, whatever):
-        self.write_pos()
-    handle_charref = handle_misc
-    handle_entityref = handle_misc
-    handle_data = handle_misc
-    handle_comment = handle_misc
-    handle_decl = handle_misc
-    handle_pi = handle_misc
-    unknown_decl = handle_misc
-
     def handle_endtag(self, tag):
         self.write_pos()
         if tag == 'textarea':
@@ -530,9 +462,6 @@
                     return True
         return str(obj) == value
 
-    def write_text(self, text):
-        self._content.append(text)
-
     def write_marker(self, marker):
         self._content.append((marker,))
 
@@ -544,68 +473,6 @@
         else:
             self._content.insert(0, text)
 
-    def write_tag(self, tag, attrs, startend=False):
-        attr_text = ''.join([' %s="%s"' % (n, html_quote(v))
-                             for (n, v) in attrs
-                             if not n.startswith('form:')])
-        if startend:
-            attr_text += " /"
-        self.write_text('<%s%s>' % (tag, attr_text))
-
-    def write_pos(self):
-        cur_line, cur_offset = self.getpos()
-        if self.in_textarea or self.skip_error:
-            self.source_pos = self.getpos()
-            return
-        if self.skip_next:
-            self.skip_next = False
-            self.source_pos = self.getpos()
-            return
-        if cur_line == self.source_pos[0]:
-            self.write_text(
-                self.lines[cur_line-1][self.source_pos[1]:cur_offset])
-        else:
-            self.write_text(
-                self.lines[self.source_pos[0]-1][self.source_pos[1]:])
-            self.write_text('\n')
-            for i in range(self.source_pos[0]+1, cur_line):
-                self.write_text(self.lines[i-1])
-                self.write_text('\n')
-            self.write_text(self.lines[cur_line-1][:cur_offset])
-        self.source_pos = self.getpos()
-
-    def get_attr(self, attr, name, default=None):
-        for n, value in attr:
-            if n.lower() == name:
-                return value
-        return default
-
-    def set_attr(self, attr, name, value):
-        for i in range(len(attr)):
-            if attr[i][0].lower() == name:
-                attr[i] = (name, value)
-                return
-        attr.append((name, value))
-
-    def del_attr(self, attr, name):
-        for i in range(len(attr)):
-            if attr[i][0].lower() == name:
-                del attr[i]
-                break
-
-    def add_class(self, attr, class_name):
-        current = self.get_attr(attr, 'class', '')
-        new = current + ' ' + class_name
-        self.set_attr(attr, 'class', new.strip())
-            
-    def text(self):
-        try:
-            return self._text
-        except AttributeError:
-            raise Exception(
-                "You must .close() a parser instance before getting "
-                "the text from it")
-
 # This can potentially be extended globally
 default_formatter_dict = {'default': default_formatter,
                           'none': none_formatter,

Added: FormEncode/trunk/formencode/htmlrename.py
===================================================================
--- FormEncode/trunk/formencode/htmlrename.py                           (rev 0)
+++ FormEncode/trunk/formencode/htmlrename.py   2008-04-23 06:55:04 UTC (rev 
3395)
@@ -0,0 +1,76 @@
+"""
+Module to rename form fields
+"""
+
+import HTMLParser
+from formencode.rewritingparser import RewritingParser
+
+__all__ = ['rename', 'add_prefix']
+
+def rename(form, rename_func):
+    """
+    Rename all the form fields in the form (a string), using rename_func
+
+    rename_func will be called with one argument, the name of the
+    field, and should return a new name.
+    """
+    p = RenamingParser(rename_func)
+    p.feed(form)
+    p.close()
+    return p.text()
+
+def add_prefix(form, prefix, dotted=False):
+    """
+    Add the given prefix to all the fields in the form.
+
+    If dotted is true, then add a dot between prefix and the previous
+    name.  Empty fields will use the prefix as the name (with no dot).
+    """
+    def rename_func(field_name):
+        if dotted:
+            if field_name:
+                return prefix + '.' + field_name
+            else:
+                return prefix
+        else:
+            return prefix + field_name
+    return rename(form, rename_func)
+
+class RenamingParser(RewritingParser):
+
+    def __init__(self, rename_func):
+        RewritingParser.__init__(self)
+        self.rename_func = rename_func
+
+    def close(self):
+        self.handle_misc(None)
+        RewritingParser.close(self)
+        self._text = self._get_text()
+
+    def text(self):
+        try:
+            return self._text
+        except AttributeError:
+            raise Exception(
+                "You must .close() a parser instance before getting "
+                "the text from it")
+
+    def handle_starttag(self, tag, attrs, startend=False):
+        self.write_pos()
+        if tag in ('input', 'textarea', 'select'):
+            self.handle_field(tag, attrs, startend)
+        else:
+            return
+
+    def handle_startendtag(self, tag, attrs):
+        return self.handle_starttag(tag, attrs, True)
+
+    def handle_field(self, tag, attrs, startend):
+        name = self.get_attr(attrs, 'name', '')
+        new_name = self.rename_func(name)
+        if name is None:
+            self.del_attr(attrs, 'name')
+        else:
+            self.set_attr(attrs, 'name', new_name)
+        self.write_tag(tag, attrs)
+        self.skip_next = True


Property changes on: FormEncode/trunk/formencode/htmlrename.py
___________________________________________________________________
Name: svn:eol-style
   + native

Added: FormEncode/trunk/formencode/rewritingparser.py
===================================================================
--- FormEncode/trunk/formencode/rewritingparser.py                              
(rev 0)
+++ FormEncode/trunk/formencode/rewritingparser.py      2008-04-23 06:55:04 UTC 
(rev 3395)
@@ -0,0 +1,153 @@
+import HTMLParser
+import re
+import cgi
+from htmlentitydefs import name2codepoint
+
+def html_quote(v):
+    if v is None:
+        return ''
+    elif hasattr(v, '__html__'):
+        return v.__html__()
+    elif isinstance(v, basestring):
+        return cgi.escape(v, 1)
+    else:
+        # @@: Should this be unicode(v) or str(v)?
+        return cgi.escape(str(v), 1)
+
+class RewritingParser(HTMLParser.HTMLParser):
+
+    listener = None
+    skip_next = False
+
+    def __init__(self):
+        self._content = []
+        HTMLParser.HTMLParser.__init__(self)
+
+    def feed(self, data):
+        self.data_is_str = isinstance(data, str)
+        self.source = data
+        self.lines = data.split('\n')
+        self.source_pos = 1, 0
+        if self.listener:
+            self.listener.reset()
+        HTMLParser.HTMLParser.feed(self, data)
+
+    _entityref_re = re.compile('&([a-zA-Z][-.a-zA-Z\d]*);')
+    _charref_re = re.compile('&#(\d+|[xX][a-fA-F\d]+);')
+
+    def unescape(self, s):
+        s = self._entityref_re.sub(self._sub_entityref, s)
+        s = self._charref_re.sub(self._sub_charref, s)
+        return s
+
+    def _sub_entityref(self, match):
+        name = match.group(1)
+        if name not in name2codepoint:
+            # If we don't recognize it, pass it through as though it
+            # wasn't an entity ref at all
+            return match.group(0)
+        return unichr(name2codepoint[name])
+
+    def _sub_charref(self, match):
+        num = match.group(1)
+        if num.lower().startswith('x'):
+            num = int(num[1:], 16)
+        else:
+            num = int(num)
+        return unichr(num)
+
+    def handle_misc(self, whatever):
+        self.write_pos()
+    handle_charref = handle_misc
+    handle_entityref = handle_misc
+    handle_data = handle_misc
+    handle_comment = handle_misc
+    handle_decl = handle_misc
+    handle_pi = handle_misc
+    unknown_decl = handle_misc
+
+    def write_tag(self, tag, attrs, startend=False):
+        attr_text = ''.join([' %s="%s"' % (n, html_quote(v))
+                             for (n, v) in attrs
+                             if not n.startswith('form:')])
+        if startend:
+            attr_text += " /"
+        self.write_text('<%s%s>' % (tag, attr_text))
+
+    def skip_output(self):
+        return False
+
+    def write_pos(self):
+        cur_line, cur_offset = self.getpos()
+        if self.skip_output():
+            self.source_pos = self.getpos()
+            return
+        if self.skip_next:
+            self.skip_next = False
+            self.source_pos = self.getpos()
+            return
+        if cur_line == self.source_pos[0]:
+            self.write_text(
+                self.lines[cur_line-1][self.source_pos[1]:cur_offset])
+        else:
+            self.write_text(
+                self.lines[self.source_pos[0]-1][self.source_pos[1]:])
+            self.write_text('\n')
+            for i in range(self.source_pos[0]+1, cur_line):
+                self.write_text(self.lines[i-1])
+                self.write_text('\n')
+            self.write_text(self.lines[cur_line-1][:cur_offset])
+        self.source_pos = self.getpos()
+
+    def write_text(self, text):
+        self._content.append(text)
+
+    def get_attr(self, attr, name, default=None):
+        for n, value in attr:
+            if n.lower() == name:
+                return value
+        return default
+
+    def set_attr(self, attr, name, value):
+        for i in range(len(attr)):
+            if attr[i][0].lower() == name:
+                attr[i] = (name, value)
+                return
+        attr.append((name, value))
+
+    def del_attr(self, attr, name):
+        for i in range(len(attr)):
+            if attr[i][0].lower() == name:
+                del attr[i]
+                break
+
+    def add_class(self, attr, class_name):
+        current = self.get_attr(attr, 'class', '')
+        new = current + ' ' + class_name
+        self.set_attr(attr, 'class', new.strip())
+            
+    def text(self):
+        try:
+            return self._text
+        except AttributeError:
+            raise Exception(
+                "You must .close() a parser instance before getting "
+                "the text from it")
+
+    def _get_text(self):
+        try:
+            return ''.join([
+                t for t in self._content if not isinstance(t, tuple)])
+        except UnicodeDecodeError, e:
+            if self.data_is_str:
+                e.reason += (
+                    " the form was passed in as an encoded string, but "
+                    "some data or error messages were unicode strings; "
+                    "the form should be passed in as a unicode string")
+            else:
+                e.reason += (
+                    " the form was passed in as an unicode string, but "
+                    "some data or error message was an encoded string; "
+                    "the data and error messages should be passed in as "
+                    "unicode strings")
+            raise


Property changes on: FormEncode/trunk/formencode/rewritingparser.py
___________________________________________________________________
Name: svn:eol-style
   + native

Added: FormEncode/trunk/tests/test_htmlrename.py
===================================================================
--- FormEncode/trunk/tests/test_htmlrename.py                           (rev 0)
+++ FormEncode/trunk/tests/test_htmlrename.py   2008-04-23 06:55:04 UTC (rev 
3395)
@@ -0,0 +1,8 @@
+from formencode.htmlrename import rename, add_prefix
+
+def test_rename():
+    assert (rename('<input type="text" name="a_name">', lambda name: 
name.upper())
+            == '<input type="text" name="A_NAME">')
+    assert (add_prefix('<input type="text" name="a_name"><input type="text" 
name="">', 'test', dotted=True)
+            == '<input type="text" name="test.a_name"><input type="text" 
name="test">')
+    


Property changes on: FormEncode/trunk/tests/test_htmlrename.py
___________________________________________________________________
Name: svn:eol-style
   + native


-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
_______________________________________________
FormEncode-CVS mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/formencode-cvs

Reply via email to