Implement new style element support
authorJeremy Stanley <fungi@yuggoth.org>
Thu, 21 Apr 2016 14:35:13 +0000 (14:35 +0000)
committerJeremy Stanley <fungi@yuggoth.org>
Thu, 21 Apr 2016 14:35:13 +0000 (14:35 +0000)
Add support for new style elements implemented as a flat associative
array of facets prefixed with their element names, and switching to
"." as a prefix separator. This is initially backward compatible
using a toggle and some sniffing of key names to distinguish old and
new style elements. Once the transition from old to new style has
been completed, the compatibility code can be cleaned up.

lib/mudpy/data.py
lib/mudpy/misc.py

index 97032e2..9c167f5 100644 (file)
@@ -84,9 +84,21 @@ class DataFile:
                         includes.append(item)
                     if item not in self.universe.private_files:
                         self.universe.private_files.append(item)
                         includes.append(item)
                     if item not in self.universe.private_files:
                         self.universe.private_files.append(item)
-        for node in self.data:
-            if node != "__control__":
-                mudpy.misc.Element(node, self.universe, self.filename)
+        for node in list(self.data):
+            if node == "__control__":
+                continue
+            facet_pos = node.rfind(".") + 1
+            if not facet_pos:
+                mudpy.misc.Element(node, self.universe, self.filename,
+                                   old_style=True)
+            else:
+                prefix = node[:facet_pos].strip(".")
+                try:
+                    element = self.universe.contents[prefix]
+                except KeyError:
+                    element = mudpy.misc.Element(prefix, self.universe,
+                        self.filename)
+                element.set(node[facet_pos:], self.data[node])
         for include_file in includes:
             if not os.path.isabs(include_file):
                 include_file = find_file(
         for include_file in includes:
             if not os.path.isabs(include_file):
                 include_file = find_file(
index f4c8779..bf107a4 100644 (file)
@@ -23,9 +23,12 @@ class Element:
 
     """An element of the universe."""
 
 
     """An element of the universe."""
 
-    def __init__(self, key, universe, filename=None):
+    def __init__(self, key, universe, filename=None, old_style=False):
         """Set up a new element."""
 
         """Set up a new element."""
 
+        # TODO(fungi): This can be removed after the transition is complete
+        self.old_style = old_style
+
         # keep track of our key name
         self.key = key
 
         # keep track of our key name
         self.key = key
 
@@ -33,7 +36,7 @@ class Element:
         self.universe = universe
 
         # clone attributes if this is replacing another element
         self.universe = universe
 
         # clone attributes if this is replacing another element
-        if self.key in self.universe.contents:
+        if self.old_style and self.key in self.universe.contents:
             old_element = self.universe.contents[self.key]
             for attribute in vars(old_element).keys():
                 exec("self." + attribute + " = old_element." + attribute)
             old_element = self.universe.contents[self.key]
             for attribute in vars(old_element).keys():
                 exec("self." + attribute + " = old_element." + attribute)
@@ -43,6 +46,9 @@ class Element:
         # i guess this is a new element then
         else:
 
         # i guess this is a new element then
         else:
 
+            # set of facet keys from the universe
+            self.facethash = dict()
+
             # not owned by a user by default (used for avatars)
             self.owner = None
 
             # not owned by a user by default (used for avatars)
             self.owner = None
 
@@ -82,7 +88,8 @@ class Element:
 
     def reload(self):
         """Create a new element and replace this one."""
 
     def reload(self):
         """Create a new element and replace this one."""
-        Element(self.key, self.universe, self.origin.filename)
+        Element(self.key, self.universe, self.origin.filename,
+                old_style=self.old_style)
         del(self)
 
     def destroy(self):
         del(self)
 
     def destroy(self):
@@ -94,10 +101,13 @@ class Element:
 
     def facets(self):
         """Return a list of non-inherited facets for this element."""
 
     def facets(self):
         """Return a list of non-inherited facets for this element."""
-        try:
-            return self.origin.data[self.key].keys()
-        except (AttributeError, KeyError):
-            return []
+        if self.old_style:
+            try:
+                return self.origin.data[self.key].keys()
+            except (AttributeError, KeyError):
+                return []
+        else:
+            return self.facethash
 
     def has_facet(self, facet):
         """Return whether the non-inherited facet exists."""
 
     def has_facet(self, facet):
         """Return whether the non-inherited facet exists."""
@@ -129,7 +139,10 @@ class Element:
         if default is None:
             default = ""
         try:
         if default is None:
             default = ""
         try:
-            return self.origin.data[self.key][facet]
+            if self.old_style:
+                return self.origin.data[self.key][facet]
+            else:
+                return self.origin.data[".".join((self.key, facet))]
         except (KeyError, TypeError):
             pass
         if self.has_facet("inherit"):
         except (KeyError, TypeError):
             pass
         if self.has_facet("inherit"):
@@ -142,9 +155,14 @@ class Element:
     def set(self, facet, value):
         """Set values."""
         if not self.has_facet(facet) or not self.get(facet) == value:
     def set(self, facet, value):
         """Set values."""
         if not self.has_facet(facet) or not self.get(facet) == value:
-            if self.key not in self.origin.data:
-                self.origin.data[self.key] = {}
-            self.origin.data[self.key][facet] = value
+            if self.old_style:
+                if self.key not in self.origin.data:
+                    self.origin.data[self.key] = {}
+                self.origin.data[self.key][facet] = value
+            else:
+                node = ".".join((self.key, facet))
+                self.origin.data[node] = value
+                self.facethash[node] = self.origin.data[node]
             self.origin.modified = True
 
     def append(self, facet, value):
             self.origin.modified = True
 
     def append(self, facet, value):
@@ -930,7 +948,7 @@ class User:
             "actor:avatar:" + self.account.get("name") + ":" + str(
                 counter
             ),
             "actor:avatar:" + self.account.get("name") + ":" + str(
                 counter
             ),
-            universe
+            universe, old_style=True
         )
         self.avatar.append("inherit", "archetype:avatar")
         self.account.append("avatars", self.avatar.key)
         )
         self.avatar.append("inherit", "archetype:avatar")
         self.account.append("avatars", self.avatar.key)
@@ -1380,7 +1398,7 @@ def on_pulse():
     # add an element for counters if it doesn't exist
     if "counters" not in universe.categories["internal"]:
         universe.categories["internal"]["counters"] = Element(
     # add an element for counters if it doesn't exist
     if "counters" not in universe.categories["internal"]:
         universe.categories["internal"]["counters"] = Element(
-            "internal:counters", universe
+            "internal:counters", universe, old_style=True
         )
 
     # update the log every now and then
         )
 
     # update the log every now and then
@@ -1718,7 +1736,7 @@ def handler_entering_account_name(user):
 
         # otherwise, this could be a brand new user
         else:
 
         # otherwise, this could be a brand new user
         else:
-            user.account = Element("account:" + name, universe)
+            user.account = Element("account:" + name, universe, old_style=True)
             user.account.set("name", name)
             log("New user: " + name, 2)
             user.state = "checking_new_account_name"
             user.account.set("name", name)
             log("New user: " + name, 2)
             user.state = "checking_new_account_name"
@@ -2173,8 +2191,12 @@ def command_show(actor, parameters):
                        + "\"):$(eol)")
             facets = element.facets()
             for facet in sorted(facets):
                        + "\"):$(eol)")
             facets = element.facets()
             for facet in sorted(facets):
-                message += ("$(eol)   $(grn)%s: $(red)%s$(nrm)" %
-                            (facet, escape_macros(element.get(facet))))
+                if element.old_style:
+                    message += ("$(eol)   $(grn)%s: $(red)%s$(nrm)" %
+                                (facet, escape_macros(element.get(facet))))
+                else:
+                    message += ("$(eol)   $(grn)%s: $(red)%s$(nrm)" %
+                                (facet, str(facets[facet])))
         else:
             message = "Element \"" + arguments[1] + "\" does not exist."
     elif arguments[0] == "result":
         else:
             message = "Element \"" + arguments[1] + "\" does not exist."
     elif arguments[0] == "result":
@@ -2248,7 +2270,7 @@ def command_create(actor, parameters):
                             " Warning: \"" + filename + "\" is not yet "
                             "included in any other file and will not be read "
                             "on startup unless this is remedied.")
                             " Warning: \"" + filename + "\" is not yet "
                             "included in any other file and will not be read "
                             "on startup unless this is remedied.")
-                Element(element, universe, filename)
+                Element(element, universe, filename, old_style=True)
                 log(logline, 6)
         elif len(arguments) > 2:
             message = "You can only specify an element and a filename."
                 log(logline, 6)
         elif len(arguments) > 2:
             message = "You can only specify an element and a filename."