implement comments properly
authorTero Marttila <terom@fixme.fi>
Thu, 02 Apr 2009 21:11:01 +0300
changeset 3 ff98fa9b84ce
parent 2 e66102ab7048
child 4 8b633782f02d
implement comments properly
conf.py
dhcp_conf.py
test_dhcp.py
--- a/conf.py	Thu Apr 02 20:54:37 2009 +0300
+++ b/conf.py	Thu Apr 02 21:11:01 2009 +0300
@@ -9,6 +9,22 @@
         An object that can be written to a ConfFile, as multiple lines of text.
     """
 
+    def __init__ (self, comments=None) :
+        """
+            Initialize with the given list of comments. Comments that are None should be ignore.
+        """
+        
+        # init the comments list
+        self.comments = comments or []
+
+    def add_comment (self, comment) :
+        """
+            Add a comment to be rendered in the output.
+        """
+        
+        # add it
+        self.comments.append(comment)
+
     def fmt_lines (self) :
         """
             Yield a series of lines to be output in the file
--- a/dhcp_conf.py	Thu Apr 02 20:54:37 2009 +0300
+++ b/dhcp_conf.py	Thu Apr 02 21:11:01 2009 +0300
@@ -6,12 +6,24 @@
 
 import itertools
 
-class Comment (conf.ConfObject) :
+class Object (conf.ConfObject) :
+    """
+        Our version of ConfObject
+    """
+    
+    def _fmt_comments (self) :
+        """
+            Format our comment lines
+        """
+        
+        for comment in self.comments :
+            if comment is not None :
+                yield "# %s" % (comment, )
+
+
+class Comment (Object) :
     """
         A comment, is, well, a comment :)
-
-        Currently, comments are only one line, and look like the following:
-            "#" <comment>
     """
 
     def __init__ (self, comment) :
@@ -19,18 +31,18 @@
             @param comment the comment string
         """
 
-        self.comment = comment
+        Object.__init__(self, [comment])
     
     def fmt_lines (self) :
         """
             Yield a single line with the comment
         """
 
-        yield "# %s" % (self.comment, )
+        return self._fmt_comments()
 
-class Section (conf.ConfObject) :
+class _Section (Object) :
     """
-        A section holds a list of params and a list of decls
+        Base implementation of Section, but doesn't format comments in output (inheriting class can define how that happens)
     """
 
     def __init__ (self, params=None, decls=None, comment=None) :
@@ -39,10 +51,11 @@
 
             If a comment is given, then it will be formatted before the section's stuff
         """
+        
+        Object.__init__(self, [comment])
 
         self.params = params or []
         self.decls = decls or []
-        self.comment = comment
 
     def add_param (self, param) :
         """
@@ -66,23 +79,11 @@
         for decl in decls :
             self.add_decl(decl)
 
-    def _fmt_comment (self) :
-        """
-            Format our comment line 
-        """
-
-        return "# %s" % (self.comment, )
-
-
     def fmt_lines (self) :
         """
             Format all of our params and decls, in that order
         """
 
-        # comment?
-        if self.comment :
-            yield self._fmt_comment()
-
         # then output each content line
         for stmt in itertools.chain(self.params, self.decls) :
             # skip Nones
@@ -92,6 +93,24 @@
             for line in stmt.fmt_lines() :
                 yield line
 
+class Section (_Section) :
+    """
+        A section holds a list of params and a list of decls, plus some comments at the beginning of the section
+    """
+    
+    def fmt_lines (self) :
+        """
+            Format all of our comments, and then super
+        """
+
+        # comments
+        for line in self._fmt_comments() :
+            yield line
+
+        # section stuff
+        for line in _Section.fmt_lines(self) :
+            yield line
+
 class ConfFile (Section, conf.File) :
     DEFAULT_NAME = "dhcpd.conf"
     DEFAULT_PATH = "/etc/dhcp3/dhcpd.conf"
@@ -104,16 +123,22 @@
         conf.File.__init__(self, name, path)
         Section.__init__(self, params, decls)
 
-class Statement (conf.ConfObject) :
+class Statement (Object) :
     """
         A statement is a single line in the config file
     """
 
-    def __init__ (self, name, *args) :
+    def __init__ (self, name, *args, **kwargs) :
         """
             Arguments given as None will be ignored.
+
+            A comment can be given as a keyword argument
         """
 
+        if kwargs : assert len(kwargs) == 1 and 'comment' in kwargs
+
+        Object.__init__(self, [kwargs.get('comment')])
+
         self.name = name
         self.args = [arg for arg in args if arg is not None]
     
@@ -186,10 +211,15 @@
         """
             Yields a single ;-terminated line
         """
-
+        
+        # comments
+        for line in self._fmt_comments() :
+            yield line
+        
+        # the line
         yield "%s;" % self._fmt_data()
 
-class Declaration (Section, Statement) :
+class Declaration (_Section, Statement) :
     """
         A declaration begins like a statement (with name and args), but then contains a curly-braces-delimited block
         that acts like a Section.
@@ -200,26 +230,30 @@
         
     """
 
-    def __init__ (self, name, args=[], params=None, decls=None) :
+    def __init__ (self, name, args=[], params=None, decls=None, comment=None) :
         """
             The name/args will be formatted as in Statement, but params should be an iterable of Parameters, and decls
             an iterable of Declarations.
         """
         
         # init the statement bit
-        Section.__init__(self, params, decls)
-        Statement.__init__(self, name, *args)
+        _Section.__init__(self, params, decls)
+        Statement.__init__(self, name, *args, **dict(comment=comment))
 
     def fmt_lines (self) :
         """
             Yields a header line, a series of indented body lines, and the footer line
         """
         
+        # comments
+        for line in self._fmt_comments() :
+            yield line
+        
         # the header to open the block
         yield "%s {" % self._fmt_data()
         
         # then output the section stuff, indented
-        for line in Section.fmt_lines(self) :
+        for line in _Section.fmt_lines(self) :
             yield "\t%s" % line
 
         # and then close the block
--- a/test_dhcp.py	Thu Apr 02 20:54:37 2009 +0300
+++ b/test_dhcp.py	Thu Apr 02 21:11:01 2009 +0300
@@ -53,6 +53,7 @@
 
     def test_parameter (self) :
         self.assert_obj(dhcpc.Parameter("param0", "this", 13, "that"),      [ "param0 this 13 that;" ])
+        self.assert_obj(dhcpc.Parameter("param1", comment="testing"),       [ "# testing", "param1;" ])
     
     def test_declaration (self) :
         self.assert_obj(dhcpc.Declaration("decl0", ["arg0", "arg1"], [
@@ -62,8 +63,8 @@
             dhcpc.Declaration("decl0.0", params=[
                 dhcpc.Parameter("param0.0.1", "value")
             ])
-        ]),  [
-            
+        ], comment="foo"),  [
+            "# foo",
             "decl0 arg0 arg1 {",
             "\tparam0;",
             "\tdecl0.0 {",