refactor out an Exports class as sub class of Parameters
diff --git a/reclass/cli.py b/reclass/cli.py
index 17467cd..7083917 100644
--- a/reclass/cli.py
+++ b/reclass/cli.py
@@ -30,6 +30,7 @@
         storage = get_storage(options.storage_type, options.nodes_uri,
                               options.classes_uri, options.exports_uri,
                               default_environment='base')
+
         class_mappings = defaults.get('class_mappings')
         reclass = Core(storage, class_mappings)
 
diff --git a/reclass/core.py b/reclass/core.py
index 1495a4c..4d5931a 100644
--- a/reclass/core.py
+++ b/reclass/core.py
@@ -17,7 +17,7 @@
 import string
 import yaml
 from reclass.output.yaml_outputter import ExplicitDumper
-from reclass.datatypes import Entity, Classes, Parameters
+from reclass.datatypes import Entity, Classes, Parameters, Exports
 from reclass.errors import MappingFormatError, ClassNotFound
 from reclass.defaults import AUTOMATIC_RECLASS_PARAMETERS
 
@@ -120,7 +120,6 @@
         else:
             return Parameters()
 
-
     def _nodeinfo(self, nodename, exports):
         node_entity = self._storage.get_node(nodename)
         base_entity = Entity(name='base')
@@ -155,7 +154,7 @@
             return False
 
     def nodeinfo(self, nodename):
-        original_exports = Parameters(self._storage.get_exports())
+        original_exports = Exports(self._storage.get_exports())
         exports = copy.deepcopy(original_exports)
         original_exports.render_simple()
         ret = self._nodeinfo_as_dict(nodename, self._nodeinfo(nodename, exports))
@@ -163,7 +162,7 @@
         return ret
 
     def inventory(self):
-        original_exports = Parameters(self._storage.get_exports())
+        original_exports = Exports(self._storage.get_exports())
         exports = copy.deepcopy(original_exports)
         original_exports.render_simple()
         nodes = { key for key in exports.as_dict()}
diff --git a/reclass/datatypes/__init__.py b/reclass/datatypes/__init__.py
index 20f7551..b506de0 100644
--- a/reclass/datatypes/__init__.py
+++ b/reclass/datatypes/__init__.py
@@ -9,4 +9,5 @@
 from applications import Applications
 from classes import Classes
 from entity import Entity
+from exports import Exports
 from parameters import Parameters
diff --git a/reclass/datatypes/entity.py b/reclass/datatypes/entity.py
index 60c15df..f73c137 100644
--- a/reclass/datatypes/entity.py
+++ b/reclass/datatypes/entity.py
@@ -8,6 +8,7 @@
 #
 from classes import Classes
 from applications import Applications
+from exports import Exports
 from parameters import Parameters
 
 class Entity(object):
@@ -23,7 +24,7 @@
         if applications is None: applications = Applications()
         self._set_applications(applications)
         if parameters is None: parameters = Parameters()
-        if exports is None: exports = Parameters()
+        if exports is None: exports = Exports()
         self._set_parameters(parameters)
         self._set_exports(exports)
         self._uri = uri or ''
@@ -58,7 +59,7 @@
         self._parameters = parameters
 
     def _set_exports(self, exports):
-        if not isinstance(exports, Parameters):
+        if not isinstance(exports, Exports):
             raise TypeError('Entity.exports cannot be set to '\
                             'instance of type %s' % type(exports))
         self._exports = exports
diff --git a/reclass/datatypes/exports.py b/reclass/datatypes/exports.py
new file mode 100644
index 0000000..ea81912
--- /dev/null
+++ b/reclass/datatypes/exports.py
@@ -0,0 +1,34 @@
+#
+# -*- coding: utf-8 -*-
+#
+# This file is part of reclass (http://github.com/madduck/reclass)
+#
+from parameters import Parameters
+
+class Exports(Parameters):
+
+    def __init__(self, mapping=None, delimiter=None):
+        super(Exports, self).__init__(mapping, delimiter)
+
+    def __repr__(self):
+        return '%s(%r, %r)' % (self.__class__.__name__, self._base,
+                               self.delimiter)
+
+    def delete_key(self, key):
+        self._base.pop(key, None)
+        self._unrendered.pop(key, None)
+
+    def overwrite(self, other):
+        overdict = {'~' + key: value for key, value in other.iteritems()}
+        self.merge(overdict)
+
+    def interpolate_from_external(self, external, options=None):
+        self._initialise_interpolate(options)
+        external._initialise_interpolate(options)
+        while len(self._unrendered) > 0:
+            path, v = self._unrendered.iteritems().next()
+            value = path.get_value(self._base)
+            external._interpolate_references(path, value, None)
+            new = value.render(external._base, self._options)
+            path.set_value(self._base, new)
+            del self._unrendered[path]
diff --git a/reclass/datatypes/parameters.py b/reclass/datatypes/parameters.py
index 6d2f334..fc6448b 100644
--- a/reclass/datatypes/parameters.py
+++ b/reclass/datatypes/parameters.py
@@ -54,9 +54,9 @@
         self._options = None
         if mapping is not None:
             # we initialise by merging
-            self._initmerge = True
+            self._keep_overrides = True
             self.merge(mapping)
-            self._initmerge = False
+            self._keep_overrides = False
 
     delimiter = property(lambda self: self._delimiter)
 
@@ -65,7 +65,7 @@
 
     def __repr__(self):
         return '%s(%r, %r)' % (self.__class__.__name__, self._base,
-                               self.delimiter)
+                               self._delimiter)
 
     def __eq__(self, other):
         return isinstance(other, type(self)) \
@@ -75,10 +75,6 @@
     def __ne__(self, other):
         return not self.__eq__(other)
 
-    def delete_key(self, key):
-        self._base.pop(key, None)
-        self._unrendered.pop(key, None)
-
     def as_dict(self):
         return self._base.copy()
 
@@ -137,24 +133,10 @@
 
         """
 
-        if isinstance(cur, dict):
-            ret = cur
-        else:
-            # nothing sensible to do
-            raise TypeError('Cannot merge dict into {0} '
-                            'objects'.format(type(cur)))
-
-        if self.delimiter is None:
-            # a delimiter of None indicates that there is no value
-            # processing to be done, and since there is no current
-            # value, we do not need to walk the new dictionary:
-            ret.update(new)
-            return ret
-
+        ret = cur
         ovrprfx = Parameters.DICT_KEY_OVERRIDE_PREFIX
-
         for key, newvalue in new.iteritems():
-            if key.startswith(ovrprfx) and not self._initmerge:
+            if key.startswith(ovrprfx) and not self._keep_overrides:
                 ret[key.lstrip(ovrprfx)] = newvalue
             else:
                 ret[key] = self._merge_recurse(ret.get(key), newvalue, path.new_subpath(key))
@@ -180,7 +162,7 @@
         """
 
 
-        if isinstance(new, dict) and (cur is None or isinstance(cur, (dict))):
+        if isinstance(new, dict) and (cur is None or isinstance(cur, dict)):
             if cur is None:
                 cur = {}
             return self._merge_dict(cur, new, path)
@@ -206,19 +188,15 @@
         if isinstance(other, dict):
             wrapped = copy.deepcopy(other)
             self._wrap_dict(wrapped)
-            self._base = self._merge_recurse(self._base, wrapped, DictPath(self.delimiter))
+            self._base = self._merge_recurse(self._base, wrapped, DictPath(self._delimiter))
 
         elif isinstance(other, self.__class__):
-            self._base = self._merge_recurse(self._base, other._base, DictPath(self.delimiter))
+            self._base = self._merge_recurse(self._base, other._base, DictPath(self._delimiter))
 
         else:
             raise TypeError('Cannot merge %s objects into %s' % (type(other),
                             self.__class__.__name__))
 
-    def overwrite(self, other):
-        overdict = {'~' + key: value for key, value in other.iteritems()}
-        self.merge(overdict)
-
     def render_simple(self, options=None):
         self._unrendered = None
         self._initialise_interpolate(options)
@@ -252,27 +230,6 @@
         for n, value in enumerate(item_list):
             self._render_simple_container(item_list, n, value, path)
 
-    def _initialise_interpolate(self, options):
-        if options is None:
-            self._options = MergeOptions()
-        else:
-            self._options = options
-
-        if self._unrendered is None:
-            self._unrendered = {}
-            self._render_simple_dict(self._base, DictPath(self.delimiter))
-
-    def interpolate_from_external(self, external, options=None):
-        self._initialise_interpolate(options)
-        external._initialise_interpolate(options)
-        while len(self._unrendered) > 0:
-            path, v = self._unrendered.iteritems().next()
-            value = path.get_value(self._base)
-            external._interpolate_references(path, value, None)
-            new = value.render(external._base, self._options)
-            path.set_value(self._base, new)
-            del self._unrendered[path]
-
     def interpolate(self, exports=None, options=None):
         self._initialise_interpolate(options)
         while len(self._unrendered) > 0:
@@ -282,6 +239,16 @@
             path, v = self._unrendered.iteritems().next()
             self._interpolate_inner(path, exports)
 
+    def _initialise_interpolate(self, options):
+        if options is None:
+            self._options = MergeOptions()
+        else:
+            self._options = options
+
+        if self._unrendered is None:
+            self._unrendered = {}
+            self._render_simple_dict(self._base, DictPath(self._delimiter))
+
     def _interpolate_inner(self, path, exports):
         value = path.get_value(self._base)
         if not isinstance(value, (Value, ValueList)):
@@ -312,7 +279,7 @@
         all_refs = False
         while not all_refs:
             for ref in value.get_references():
-                path_from_ref = DictPath(self.delimiter, ref)
+                path_from_ref = DictPath(self._delimiter, ref)
 
                 if path_from_ref in self._unrendered:
                     if self._unrendered[path_from_ref] is False:
@@ -326,7 +293,7 @@
                         self._interpolate_inner(path_from_ref, exports)
                 else:
                     # ensure ancestor keys are already dereferenced
-                    ancestor = DictPath(self.delimiter)
+                    ancestor = DictPath(self._delimiter)
                     for k in path_from_ref.key_parts():
                         ancestor = ancestor.new_subpath(k)
                         if ancestor in self._unrendered:
diff --git a/reclass/datatypes/tests/test_entity.py b/reclass/datatypes/tests/test_entity.py
index c583bfd..76b90b9 100644
--- a/reclass/datatypes/tests/test_entity.py
+++ b/reclass/datatypes/tests/test_entity.py
@@ -6,7 +6,7 @@
 # Copyright © 2007–14 martin f. krafft <madduck@madduck.net>
 # Released under the terms of the Artistic Licence 2.0
 #
-from reclass.datatypes import Entity, Classes, Parameters, Applications
+from reclass.datatypes import Entity, Classes, Parameters, Applications, Exports
 import unittest
 try:
     import unittest.mock as mock
@@ -14,11 +14,12 @@
     import mock
 
 @mock.patch.multiple('reclass.datatypes', autospec=True, Classes=mock.DEFAULT,
-                     Applications=mock.DEFAULT, Parameters=mock.DEFAULT)
+                     Applications=mock.DEFAULT, Parameters=mock.DEFAULT,
+                     Exports=mock.DEFAULT)
 class TestEntity(unittest.TestCase):
 
-    def _make_instances(self, Classes, Applications, Parameters):
-        return Classes(), Applications(), Parameters(), mock.MagicMock(spec=Parameters)
+    def _make_instances(self, Classes, Applications, Parameters, Exports):
+        return Classes(), Applications(), Parameters(), Exports()
 
     def test_constructor_default(self, **mocks):
         # Actually test the real objects by calling the default constructor,
@@ -29,7 +30,7 @@
         self.assertIsInstance(e.classes, Classes)
         self.assertIsInstance(e.applications, Applications)
         self.assertIsInstance(e.parameters, Parameters)
-        self.assertIsInstance(e.exports, Parameters)
+        self.assertIsInstance(e.exports, Exports)
 
     def test_constructor_empty(self, **types):
         instances = self._make_instances(**types)
@@ -157,9 +158,9 @@
 class TestEntityNoMock(unittest.TestCase):
 
     def test_exports_with_refs(self):
-        exports = Parameters({'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}})
+        exports = Exports({'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}})
         exports_entity = Entity(None, None, None, exports)
-        node3_exports = Parameters({'a': '${a}', 'b': '${b}'})
+        node3_exports = Exports({'a': '${a}', 'b': '${b}'})
         node3_parameters = Parameters({'name': 'node3', 'a': '${c}', 'b': 5})
         node3_parameters.merge({'c': 3})
         node3_entity = Entity(None, None, node3_parameters, node3_exports)
@@ -168,9 +169,9 @@
         self.assertDictEqual(exports.as_dict(), r)
 
     def test_reference_to_an_export(self):
-        exports = Parameters({'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}})
+        exports = Exports({'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}})
         exports_entity = Entity(None, None, None, exports)
-        node3_exports = Parameters({'a': '${a}', 'b': '${b}'})
+        node3_exports = Exports({'a': '${a}', 'b': '${b}'})
         node3_parameters = Parameters({'name': 'node3', 'ref': '${exp}', 'a': '${c}', 'b': 5})
         node3_parameters.merge({'c': 3, 'exp': '$[ exports:a ]'})
         node3_entity = Entity(None, None, node3_parameters, node3_exports)
@@ -179,9 +180,9 @@
         self.assertDictEqual(exports.as_dict(), r)
 
     def test_exports_with_nested_references(self):
-        exports = Parameters({'node1': {'alpha': {'a': 1, 'b': 2}}, 'node2': {'alpha': {'a': 3, 'b': 4}}})
+        exports = Exports({'node1': {'alpha': {'a': 1, 'b': 2}}, 'node2': {'alpha': {'a': 3, 'b': 4}}})
         exports_entity = Entity(None, None, None, exports)
-        node3_exports = Parameters({'alpha': '${alpha}'})
+        node3_exports = Exports({'alpha': '${alpha}'})
         node3_parameters = Parameters({'name': 'node3', 'alpha': {'a': '${one}', 'b': '${two}'}, 'beta': '$[ exports:alpha ]', 'one': '111', 'two': '${three}', 'three': '123'})
         node3_entity = Entity(None, None, node3_parameters, node3_exports)
         res_params = {'beta': {'node1': {'a': 1, 'b': 2}, 'node3': {'a': '111', 'b': '123'}, 'node2': {'a': 3, 'b': 4}}, 'name': 'node3', 'alpha': {'a': '111', 'b': '123'}, 'three': '123', 'two': '123', 'one': '111'}
diff --git a/reclass/datatypes/tests/test_exports.py b/reclass/datatypes/tests/test_exports.py
new file mode 100644
index 0000000..f1b960b
--- /dev/null
+++ b/reclass/datatypes/tests/test_exports.py
@@ -0,0 +1,45 @@
+#
+# -*- coding: utf-8 -*-
+#
+# This file is part of reclass (http://github.com/madduck/reclass)
+#
+
+from reclass.datatypes import Exports, Parameters
+import unittest
+try:
+    import unittest.mock as mock
+except ImportError:
+    import mock
+
+class TestExportsNoMock(unittest.TestCase):
+
+    def test_overwrite_method(self):
+        e = Exports({'alpha': { 'one': 1, 'two': 2}})
+        d = {'alpha': { 'three': 3, 'four': 4}}
+        e.overwrite(d)
+        e.render_simple()
+        self.assertEqual(e.as_dict(), d)
+
+    def test_value_expr_exports(self):
+        e = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
+        p = Parameters({'exp': '$[ exports:a ]'})
+        r = {'exp': {'node1': 1, 'node2': 3}}
+        p.interpolate(e)
+        self.assertEqual(p.as_dict(), r)
+
+    def test_if_expr_exports(self):
+        e = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
+        p = Parameters({'exp': '$[ exports:a if exports:b == 4 ]'})
+        r = {'exp': {'node2': 3}}
+        p.interpolate(e)
+        self.assertEqual(p.as_dict(), r)
+
+    def test_if_expr_exports_with_refs(self):
+        e = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
+        p = Parameters({'exp': '$[ exports:a if exports:b == self:test_value ]', 'test_value': 2})
+        r = {'exp': {'node1': 1}, 'test_value': 2}
+        p.interpolate(e)
+        self.assertEqual(p.as_dict(), r)
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/reclass/datatypes/tests/test_parameters.py b/reclass/datatypes/tests/test_parameters.py
index 093c28c..1cc3804 100644
--- a/reclass/datatypes/tests/test_parameters.py
+++ b/reclass/datatypes/tests/test_parameters.py
@@ -401,33 +401,5 @@
         p1.interpolate()
         self.assertEqual(p1.as_dict(), r)
 
-    def test_overwrite_method(self):
-        p = Parameters({'alpha': { 'one': 1, 'two': 2}})
-        d = {'alpha': { 'three': 3, 'four': 4}}
-        p.overwrite(d)
-        p.render_simple()
-        self.assertEqual(p.as_dict(), d)
-
-    def test_value_expr_exports(self):
-        e = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
-        p = Parameters({'exp': '$[ exports:a ]'})
-        r = {'exp': {'node1': 1, 'node2': 3}}
-        p.interpolate(e)
-        self.assertEqual(p.as_dict(), r)
-
-    def test_if_expr_exports(self):
-        e = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
-        p = Parameters({'exp': '$[ exports:a if exports:b == 4 ]'})
-        r = {'exp': {'node2': 3}}
-        p.interpolate(e)
-        self.assertEqual(p.as_dict(), r)
-
-    def test_if_expr_exports_with_refs(self):
-        e = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
-        p = Parameters({'exp': '$[ exports:a if exports:b == self:test_value ]', 'test_value': 2})
-        r = {'exp': {'node1': 1}, 'test_value': 2}
-        p.interpolate(e)
-        self.assertEqual(p.as_dict(), r)
-
 if __name__ == '__main__':
     unittest.main()
diff --git a/reclass/storage/yaml_fs/yamlfile.py b/reclass/storage/yaml_fs/yamlfile.py
index dcd6df4..ad262cd 100644
--- a/reclass/storage/yaml_fs/yamlfile.py
+++ b/reclass/storage/yaml_fs/yamlfile.py
@@ -53,7 +53,7 @@
         exports = self._data.get('exports')
         if exports is None:
             exports = {}
-        exports = datatypes.Parameters(exports)
+        exports = datatypes.Exports(exports)
 
         if name is None:
             name = self._path