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)
-        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(
index f4c8779..bf107a4 100644 (file)
@@ -23,9 +23,12 @@ class Element:
 
     """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."""
 
+        # 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
 
@@ -33,7 +36,7 @@ class 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)
@@ -43,6 +46,9 @@ class Element:
         # 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
 
@@ -82,7 +88,8 @@ class Element:
 
     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):
@@ -94,10 +101,13 @@ class 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."""
@@ -129,7 +139,10 @@ class Element:
         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"):
@@ -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:
-            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):
@@ -930,7 +948,7 @@ class User:
             "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)
@@ -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(
-            "internal:counters", universe
+            "internal:counters", universe, old_style=True
         )
 
     # 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:
-            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"
@@ -2173,8 +2191,12 @@ def command_show(actor, parameters):
                        + "\"):$(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":
@@ -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.")
-                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."