consolidate settings into an object that can be passed around
diff --git a/reclass/adapters/ansible.py b/reclass/adapters/ansible.py
index 6794a0d..1bf509d 100755
--- a/reclass/adapters/ansible.py
+++ b/reclass/adapters/ansible.py
@@ -10,6 +10,9 @@
 # Copyright © 2007–14 martin f. krafft <madduck@madduck.net>
 # Released under the terms of the Artistic Licence 2.0
 #
+# 2017.08.08 Andew Pickford <anpickford@googlemail.com>
+# The ansible adapter has received little testing and may not work at all now.
+
 
 import os, sys, posix, optparse
 
@@ -19,6 +22,7 @@
 from reclass.config import find_and_read_configfile, get_options
 from reclass.version import *
 from reclass.constants import MODE_NODEINFO
+from reclass.settings import Settings
 
 def cli():
     try:
@@ -57,7 +61,8 @@
 
         storage = get_storage(options.storage_type, options.nodes_uri, options.classes_uri)
         class_mappings = defaults.get('class_mappings')
-        reclass = Core(storage, class_mappings, default_environment=None)
+        settings = Settings(defaults)
+        reclass = Core(storage, class_mappings, settings)
 
         if options.mode == MODE_NODEINFO:
             data = reclass.nodeinfo(options.hostname)
diff --git a/reclass/adapters/salt.py b/reclass/adapters/salt.py
index beca9e5..4d6cccc 100755
--- a/reclass/adapters/salt.py
+++ b/reclass/adapters/salt.py
@@ -15,6 +15,7 @@
 from reclass.config import find_and_read_configfile, get_options
 from reclass.constants import MODE_NODEINFO
 from reclass.defaults import *
+from reclass.settings import Settings
 from reclass.version import *
 
 def ext_pillar(minion_id, pillar,
@@ -23,7 +24,8 @@
                nodes_uri=OPT_NODES_URI,
                classes_uri=OPT_CLASSES_URI,
                class_mappings=None,
-               propagate_pillar_data_to_reclass=False):
+               propagate_pillar_data_to_reclass=False,
+               **kwargs):
 
     path_mangler = get_path_mangler(storage_type)
     nodes_uri, classes_uri = path_mangler(inventory_base_uri, nodes_uri, classes_uri)
@@ -31,7 +33,8 @@
     input_data = None
     if propagate_pillar_data_to_reclass:
         input_data = pillar
-    reclass = Core(storage, class_mappings, input_data=input_data, default_environment='base')
+    settings = Settings(kwargs)
+    reclass = Core(storage, class_mappings, settings, input_data=input_data)
 
     data = reclass.nodeinfo(minion_id)
     params = data.get('parameters', {})
diff --git a/reclass/cli.py b/reclass/cli.py
index 15df811..6023bfa 100644
--- a/reclass/cli.py
+++ b/reclass/cli.py
@@ -11,9 +11,10 @@
 
 from reclass import get_storage, output
 from reclass.core import Core
+from reclass.settings import Settings
 from reclass.config import find_and_read_configfile, get_options
-from reclass.errors import ReclassException
 from reclass.defaults import *
+from reclass.errors import ReclassException
 from reclass.constants import MODE_NODEINFO
 from reclass.version import *
 
@@ -28,7 +29,8 @@
         options = get_options(RECLASS_NAME, VERSION, DESCRIPTION, defaults=defaults)
         storage = get_storage(options.storage_type, options.nodes_uri, options.classes_uri)
         class_mappings = defaults.get('class_mappings')
-        reclass = Core(storage, class_mappings, default_environment='base')
+        settings = Settings(defaults)
+        reclass = Core(storage, class_mappings, settings)
 
         if options.mode == MODE_NODEINFO:
             data = reclass.nodeinfo(options.nodename)
diff --git a/reclass/config.py b/reclass/config.py
index 2653586..2bfaf02 100644
--- a/reclass/config.py
+++ b/reclass/config.py
@@ -11,7 +11,7 @@
 
 import errors
 from defaults import *
-from constants import MODE_NODEINFO, MODE_INVENTORY 
+from constants import MODE_NODEINFO, MODE_INVENTORY
 from reclass import get_path_mangler
 
 def make_db_options_group(parser, defaults={}):
diff --git a/reclass/core.py b/reclass/core.py
index f1de527..8082d80 100644
--- a/reclass/core.py
+++ b/reclass/core.py
@@ -14,18 +14,18 @@
 import shlex
 import string
 import yaml
+from reclass.settings import Settings
 from reclass.output.yaml_outputter import ExplicitDumper
 from reclass.datatypes import Entity, Classes, Parameters, Exports
 from reclass.errors import MappingFormatError, ClassNotFound, ResolveError
-from reclass.defaults import AUTOMATIC_RECLASS_PARAMETERS
 
 class Core(object):
 
-    def __init__(self, storage, class_mappings, input_data=None, default_environment=None):
+    def __init__(self, storage, class_mappings, settings, input_data=None):
         self._storage = storage
         self._class_mappings = class_mappings
+        self._settings = settings
         self._input_data = input_data
-        self._default_environment = default_environment
 
     @staticmethod
     def _get_timestamp():
@@ -60,7 +60,7 @@
 
     def _get_class_mappings_entity(self, nodename):
         if not self._class_mappings:
-            return Entity(name='empty (class mappings)')
+            return Entity(self._settings, name='empty (class mappings)')
         c = Classes()
         for mapping in self._class_mappings:
             matched = False
@@ -76,29 +76,29 @@
                     for klass in klasses:
                         c.append_if_new(klass)
 
-        return Entity(classes=c,
+        return Entity(self._settings, classes=c,
                       name='class mappings for node {0}'.format(nodename))
 
     def _get_input_data_entity(self):
         if not self._input_data:
-            return Entity(name='empty (input data)')
-        p = Parameters(self._input_data)
-        return Entity(parameters=p, name='input data')
+            return Entity(self._settings, name='empty (input data)')
+        p = Parameters(self._input_data, self._settings)
+        return Entity(self._settings, parameters=p, name='input data')
 
     def _recurse_entity(self, entity, merge_base=None, seen=None, nodename=None, environment=None):
         if seen is None:
             seen = {}
 
         if environment is None:
-            environment = self._default_environment
+            environment = self._settings.default_environment
 
         if merge_base is None:
-            merge_base = Entity(name='empty (@{0})'.format(nodename))
+            merge_base = Entity(self._settings, name='empty (@{0})'.format(nodename))
 
         for klass in entity.classes.as_list():
             if klass not in seen:
                 try:
-                    class_entity = self._storage.get_class(klass, environment)
+                    class_entity = self._storage.get_class(klass, environment, self._settings)
                 except ClassNotFound, e:
                     e.set_nodename(nodename)
                     raise e
@@ -117,11 +117,11 @@
         return merge_base
 
     def _get_automatic_parameters(self, nodename, environment):
-        if AUTOMATIC_RECLASS_PARAMETERS:
+        if self._settings.automatic_parameters:
             return Parameters({ '_reclass_': { 'name': { 'full': nodename, 'short': string.split(nodename, '.')[0] },
-                                               'environment': environment } })
+                                               'environment': environment } }, self._settings, '__auto__')
         else:
-            return Parameters()
+            return Parameters({}, self._settings, '')
 
     def _get_inventory(self):
         inventory = {}
@@ -136,10 +136,10 @@
         return inventory
 
     def _node_entity(self, nodename):
-        node_entity = self._storage.get_node(nodename)
+        node_entity = self._storage.get_node(nodename, self._settings)
         if node_entity.environment == None:
-            node_entity.environment = self._default_environment
-        base_entity = Entity(name='base')
+            node_entity.environment = self._settings.default_environment
+        base_entity = Entity(self._settings, name='base')
         base_entity.merge(self._get_class_mappings_entity(node_entity.name))
         base_entity.merge(self._get_input_data_entity())
         base_entity.merge_parameters(self._get_automatic_parameters(nodename, node_entity.environment))
diff --git a/reclass/datatypes/entity.py b/reclass/datatypes/entity.py
index 8ad66c0..5b54cf7 100644
--- a/reclass/datatypes/entity.py
+++ b/reclass/datatypes/entity.py
@@ -17,18 +17,18 @@
     for merging. The name and uri of an Entity will be updated to the name and
     uri of the Entity that is being merged.
     '''
-    def __init__(self, classes=None, applications=None, parameters=None,
+    def __init__(self, settings, classes=None, applications=None, parameters=None,
                  exports=None, uri=None, name=None, environment=None):
+        self._uri = uri or ''
+        self._name = name or ''
         if classes is None: classes = Classes()
         self._set_classes(classes)
         if applications is None: applications = Applications()
         self._set_applications(applications)
-        if parameters is None: parameters = Parameters()
-        if exports is None: exports = Exports()
+        if parameters is None: parameters = Parameters(None, settings, uri)
+        if exports is None: exports = Exports(None, settings, uri)
         self._set_parameters(parameters)
         self._set_exports(exports)
-        self._uri = uri or ''
-        self._name = name or ''
         self._environment = environment
 
     name = property(lambda s: s._name)
diff --git a/reclass/datatypes/exports.py b/reclass/datatypes/exports.py
index 8fbf880..f8f38a1 100644
--- a/reclass/datatypes/exports.py
+++ b/reclass/datatypes/exports.py
@@ -10,12 +10,11 @@
 
 class Exports(Parameters):
 
-    def __init__(self, mapping=None, uri=None, delimiter=None, options=None):
-        super(Exports, self).__init__(mapping, uri, delimiter, options)
+    def __init__(self, mapping, settings, uri):
+        super(Exports, self).__init__(mapping, settings, uri)
 
     def __repr__(self):
-        return '%s(%r, %r)' % (self.__class__.__name__, self._base,
-                               self.delimiter)
+        return '%s(%r)' % (self.__class__.__name__, self._base)
 
     def delete_key(self, key):
         self._base.pop(key, None)
@@ -44,7 +43,7 @@
 
     def _interpolate_render_from_external(self, context, path, value):
         try:
-            new = value.render(context, None, self._options)
+            new = value.render(context, None)
         except ResolveError as e:
             e.context = path
             raise e
diff --git a/reclass/datatypes/parameters.py b/reclass/datatypes/parameters.py
index 411f631..b55f01a 100644
--- a/reclass/datatypes/parameters.py
+++ b/reclass/datatypes/parameters.py
@@ -11,9 +11,7 @@
 import sys
 import types
 from collections import namedtuple
-from reclass.defaults import *
 from reclass.utils.dictpath import DictPath
-from reclass.values.mergeoptions import MergeOptions
 from reclass.values.value import Value
 from reclass.values.valuelist import ValueList
 from reclass.errors import InfiniteRecursionError, ResolveError, InterpolationError
@@ -41,21 +39,14 @@
     To support these specialities, this class only exposes very limited
     functionality and does not try to be a really mapping object.
     '''
-    DEFAULT_PATH_DELIMITER = PARAMETER_INTERPOLATION_DELIMITER
-    DICT_KEY_OVERRIDE_PREFIX = PARAMETER_DICT_KEY_OVERRIDE_PREFIX
 
-    def __init__(self, mapping=None, uri=None, delimiter=None, options=None):
-        if delimiter is None:
-            delimiter = Parameters.DEFAULT_PATH_DELIMITER
-        if options is None:
-            options = MergeOptions()
-        self._delimiter = delimiter
+    def __init__(self, mapping, settings, uri):
+        self._settings = settings
         self._base = {}
         self._uri = uri
         self._unrendered = None
         self._escapes_handled = {}
         self._has_inv_query = False
-        self._options = options
         self._keep_overrides = False
         if mapping is not None:
             # we initialise by merging
@@ -63,19 +54,18 @@
             self.merge(mapping)
             self._keep_overrides = False
 
-    delimiter = property(lambda self: self._delimiter)
+    #delimiter = property(lambda self: self._delimiter)
 
     def __len__(self):
         return len(self._base)
 
     def __repr__(self):
-        return '%s(%r, %r)' % (self.__class__.__name__, self._base,
-                               self._delimiter)
+        return '%s(%r)' % (self.__class__.__name__, self._base)
 
     def __eq__(self, other):
         return isinstance(other, type(self)) \
                 and self._base == other._base \
-                and self._delimiter == other._delimiter
+                and self._settings == other._settings
 
     def __ne__(self, other):
         return not self.__eq__(other)
@@ -94,7 +84,7 @@
         elif isinstance(value, (Value, ValueList)):
             return value
         else:
-            return Value(value, uri=self._uri, delimiter=self._delimiter)
+            return Value(value, self._settings, self._uri)
 
     def _wrap_list(self, source):
         return [ self._wrap_value(v) for v in source ]
@@ -104,18 +94,18 @@
 
     def _update_value(self, cur, new, path):
         if isinstance(cur, Value):
-            values = ValueList(cur)
+            values = ValueList(cur, self._settings)
         elif isinstance(cur, ValueList):
             values = cur
         else:
-            values = ValueList(Value(cur, uri=self._uri, delimiter=self._delimiter))
+            values = ValueList(Value(cur, self._settings, self._uri), self._settings)
 
         if isinstance(new, Value):
             values.append(new)
         elif isinstance(new, ValueList):
             values.extend(new)
         else:
-            values.append(Value(new, uri=self._uri, delimiter=self._delimiter))
+            values.append(Value(new, self._settings, self._uri))
 
         return values
 
@@ -139,10 +129,9 @@
         """
 
         ret = cur
-        ovrprfx = Parameters.DICT_KEY_OVERRIDE_PREFIX
         for key, newvalue in new.iteritems():
-            if key.startswith(ovrprfx) and not self._keep_overrides:
-                ret[key.lstrip(ovrprfx)] = newvalue
+            if key.startswith(self._settings.dict_key_override_prefix) and not self._keep_overrides:
+                ret[key.lstrip(self._settings.dict_key_override_prefix)] = newvalue
             else:
                 ret[key] = self._merge_recurse(ret.get(key), newvalue, path.new_subpath(key))
         return ret
@@ -196,7 +185,7 @@
         else:
             raise TypeError('Cannot merge %s objects into %s' % (type(other),
                             self.__class__.__name__))
-        self._base = self._merge_recurse(self._base, wrapped, DictPath(self._delimiter))
+        self._base = self._merge_recurse(self._base, wrapped, DictPath(self._settings.delimiter))
 
     def _render_simple_container(self, container, key, value, path):
             if isinstance(value, ValueList):
@@ -206,7 +195,7 @@
                         self._has_inv_query = True
                     return
                 else:
-                    value = value.merge(self._options)
+                    value = value.merge()
             if isinstance(value, Value) and value.is_container():
                 value = value.contents()
             if isinstance(value, dict):
@@ -221,7 +210,7 @@
                     if value.has_inv_query():
                         self._has_inv_query = True
                 else:
-                    container[key] = value.render(None, None, self._options)
+                    container[key] = value.render(None, None)
 
     def _render_simple_dict(self, dictionary, path):
         for key, value in dictionary.iteritems():
@@ -248,7 +237,7 @@
         if self._unrendered is None:
             self._unrendered = {}
             self._has_inv_query = False
-            self._render_simple_dict(self._base, DictPath(self._delimiter))
+            self._render_simple_dict(self._base, DictPath(self._settings.delimiter))
 
     def _interpolate_inner(self, path, inventory):
         value = path.get_value(self._base)
@@ -266,7 +255,7 @@
 
     def _interpolate_render_value(self, path, value, inventory):
         try:
-            new = value.render(self._base, inventory, self._options)
+            new = value.render(self._base, inventory)
         except ResolveError as e:
             e.context = path
             raise e
@@ -281,7 +270,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._settings.delimiter, ref)
 
                 if path_from_ref in self._unrendered:
                     if self._unrendered[path_from_ref] is False:
@@ -295,7 +284,7 @@
                         self._interpolate_inner(path_from_ref, inventory)
                 else:
                     # ensure ancestor keys are already dereferenced
-                    ancestor = DictPath(self._delimiter)
+                    ancestor = DictPath(self._settings.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 8f693f1..743cf0a 100644
--- a/reclass/datatypes/tests/test_entity.py
+++ b/reclass/datatypes/tests/test_entity.py
@@ -6,6 +6,8 @@
 # Copyright © 2007–14 martin f. krafft <madduck@madduck.net>
 # Released under the terms of the Artistic Licence 2.0
 #
+
+from reclass.settings import Settings
 from reclass.datatypes import Entity, Classes, Parameters, Applications, Exports
 import unittest
 try:
@@ -13,18 +15,20 @@
 except ImportError:
     import mock
 
+SETTINGS = Settings()
+
 @mock.patch.multiple('reclass.datatypes', autospec=True, Classes=mock.DEFAULT,
                      Applications=mock.DEFAULT, Parameters=mock.DEFAULT,
                      Exports=mock.DEFAULT)
 class TestEntity(unittest.TestCase):
 
     def _make_instances(self, Classes, Applications, Parameters, Exports):
-        return Classes(), Applications(), Parameters(), Exports()
+        return Classes(), Applications(), Parameters({}, SETTINGS, ""), Exports({}, SETTINGS, "")
 
     def test_constructor_default(self, **mocks):
         # Actually test the real objects by calling the default constructor,
         # all other tests shall pass instances to the constructor
-        e = Entity()
+        e = Entity(SETTINGS)
         self.assertEqual(e.name, '')
         self.assertEqual(e.uri, '')
         self.assertIsInstance(e.classes, Classes)
@@ -34,7 +38,7 @@
 
     def test_constructor_empty(self, **types):
         instances = self._make_instances(**types)
-        e = Entity(*instances)
+        e = Entity(SETTINGS, *instances)
         self.assertEqual(e.name, '')
         self.assertEqual(e.uri, '')
         cl, al, pl, ex = [getattr(i, '__len__') for i in instances]
@@ -49,51 +53,51 @@
 
     def test_constructor_empty_named(self, **types):
         name = 'empty'
-        e = Entity(*self._make_instances(**types), name=name)
+        e = Entity(SETTINGS, *self._make_instances(**types), name=name)
         self.assertEqual(e.name, name)
 
     def test_constructor_empty_uri(self, **types):
         uri = 'test://uri'
-        e = Entity(*self._make_instances(**types), uri=uri)
+        e = Entity(SETTINGS, *self._make_instances(**types), uri=uri)
         self.assertEqual(e.uri, uri)
 
     def test_constructor_empty_env(self, **types):
         env = 'not base'
-        e = Entity(*self._make_instances(**types), environment=env)
+        e = Entity(SETTINGS, *self._make_instances(**types), environment=env)
         self.assertEqual(e.environment, env)
 
     def test_equal_empty(self, **types):
         instances = self._make_instances(**types)
-        self.assertEqual(Entity(*instances), Entity(*instances))
+        self.assertEqual(Entity(SETTINGS, *instances), Entity(SETTINGS, *instances))
         for i in instances:
             i.__eq__.assert_called_once_with(i)
 
     def test_equal_empty_named(self, **types):
         instances = self._make_instances(**types)
-        self.assertEqual(Entity(*instances), Entity(*instances))
+        self.assertEqual(Entity(SETTINGS, *instances), Entity(SETTINGS, *instances))
         name = 'empty'
-        self.assertEqual(Entity(*instances, name=name),
-                         Entity(*instances, name=name))
+        self.assertEqual(Entity(SETTINGS, *instances, name=name),
+                         Entity(SETTINGS, *instances, name=name))
 
     def test_unequal_empty_uri(self, **types):
         instances = self._make_instances(**types)
         uri = 'test://uri'
-        self.assertNotEqual(Entity(*instances, uri=uri),
-                            Entity(*instances, uri=uri[::-1]))
+        self.assertNotEqual(Entity(SETTINGS, *instances, uri=uri),
+                            Entity(SETTINGS, *instances, uri=uri[::-1]))
         for i in instances:
             i.__eq__.assert_called_once_with(i)
 
     def test_unequal_empty_named(self, **types):
         instances = self._make_instances(**types)
         name = 'empty'
-        self.assertNotEqual(Entity(*instances, name=name),
-                            Entity(*instances, name=name[::-1]))
+        self.assertNotEqual(Entity(SETTINGS, *instances, name=name),
+                            Entity(SETTINGS, *instances, name=name[::-1]))
         for i in instances:
             i.__eq__.assert_called_once_with(i)
 
     def test_unequal_types(self, **types):
         instances = self._make_instances(**types)
-        self.assertNotEqual(Entity(*instances, name='empty'),
+        self.assertNotEqual(Entity(SETTINGS, *instances, name='empty'),
                             None)
         for i in instances:
             self.assertEqual(i.__eq__.call_count, 0)
@@ -101,7 +105,7 @@
     def _test_constructor_wrong_types(self, which_replace, **types):
         instances = self._make_instances(**types)
         instances[which_replace] = 'Invalid type'
-        e = Entity(*instances)
+        e = Entity(SETTINGS, *instances)
 
     def test_constructor_wrong_type_classes(self, **types):
         self.assertRaises(TypeError, self._test_constructor_wrong_types, 0)
@@ -114,7 +118,7 @@
 
     def test_merge(self, **types):
         instances = self._make_instances(**types)
-        e = Entity(*instances)
+        e = Entity(SETTINGS, *instances)
         e.merge(e)
         for i, fn in zip(instances, ('merge_unique', 'merge_unique', 'merge')):
             getattr(i, fn).assert_called_once_with(i)
@@ -122,30 +126,30 @@
     def test_merge_newname(self, **types):
         instances = self._make_instances(**types)
         newname = 'newname'
-        e1 = Entity(*instances, name='oldname')
-        e2 = Entity(*instances, name=newname)
+        e1 = Entity(SETTINGS, *instances, name='oldname')
+        e2 = Entity(SETTINGS, *instances, name=newname)
         e1.merge(e2)
         self.assertEqual(e1.name, newname)
 
     def test_merge_newuri(self, **types):
         instances = self._make_instances(**types)
         newuri = 'test://uri2'
-        e1 = Entity(*instances, uri='test://uri1')
-        e2 = Entity(*instances, uri=newuri)
+        e1 = Entity(SETTINGS, *instances, uri='test://uri1')
+        e2 = Entity(SETTINGS, *instances, uri=newuri)
         e1.merge(e2)
         self.assertEqual(e1.uri, newuri)
 
     def test_merge_newenv(self, **types):
         instances = self._make_instances(**types)
         newenv = 'new env'
-        e1 = Entity(*instances, environment='env')
-        e2 = Entity(*instances, environment=newenv)
+        e1 = Entity(SETTINGS, *instances, environment='env')
+        e2 = Entity(SETTINGS, *instances, environment=newenv)
         e1.merge(e2)
         self.assertEqual(e1.environment, newenv)
 
     def test_as_dict(self, **types):
         instances = self._make_instances(**types)
-        entity = Entity(*instances, name='test', environment='test')
+        entity = Entity(SETTINGS, *instances, name='test', environment='test')
         comp = {}
         comp['classes'] = instances[0].as_list()
         comp['applications'] = instances[1].as_list()
@@ -159,10 +163,10 @@
 
     def test_exports_with_refs(self):
         inventory = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
-        node3_exports = Exports({'a': '${a}', 'b': '${b}'})
-        node3_parameters = Parameters({'name': 'node3', 'a': '${c}', 'b': 5})
+        node3_exports = Exports({'a': '${a}', 'b': '${b}'}, SETTINGS, '')
+        node3_parameters = Parameters({'name': 'node3', 'a': '${c}', 'b': 5}, SETTINGS, '')
         node3_parameters.merge({'c': 3})
-        node3_entity = Entity(None, None, node3_parameters, node3_exports)
+        node3_entity = Entity(SETTINGS, classes=None, applications=None, parameters=node3_parameters, exports=node3_exports)
         node3_entity.interpolate_exports()
         inventory['node3'] = node3_entity.exports.as_dict()
         r = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}, 'node3': {'a': 3, 'b': 5}}
@@ -170,10 +174,10 @@
 
     def test_reference_to_an_export(self):
         inventory = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
-        node3_exports = Exports({'a': '${a}', 'b': '${b}'})
-        node3_parameters = Parameters({'name': 'node3', 'ref': '${exp}', 'a': '${c}', 'b': 5})
+        node3_exports = Exports({'a': '${a}', 'b': '${b}'}, SETTINGS, '')
+        node3_parameters = Parameters({'name': 'node3', 'ref': '${exp}', 'a': '${c}', 'b': 5}, SETTINGS, '')
         node3_parameters.merge({'c': 3, 'exp': '$[ exports:a ]'})
-        node3_entity = Entity(None, None, node3_parameters, node3_exports)
+        node3_entity = Entity(SETTINGS, classes=None, applications=None, parameters=node3_parameters, exports=node3_exports)
         node3_entity.interpolate_exports()
         inventory['node3'] = node3_entity.exports.as_dict()
         node3_entity.interpolate('node3', inventory)
@@ -184,9 +188,9 @@
 
     def test_exports_with_nested_references(self):
         inventory = {'node1': {'alpha': {'a': 1, 'b': 2}}, 'node2': {'alpha': {'a': 3, 'b': 4}}}
-        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)
+        node3_exports = Exports({'alpha': '${alpha}'}, SETTINGS, '')
+        node3_parameters = Parameters({'name': 'node3', 'alpha': {'a': '${one}', 'b': '${two}'}, 'beta': '$[ exports:alpha ]', 'one': '111', 'two': '${three}', 'three': '123'}, SETTINGS, '')
+        node3_entity = Entity(SETTINGS, classes=None, applications=None, parameters=node3_parameters, exports=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'}
         res_inv = {'node1': {'alpha': {'a': 1, 'b': 2}}, 'node2': {'alpha': {'a': 3, 'b': 4}}, 'node3': {'alpha': {'a': '111', 'b': '123'}}}
         node3_entity.interpolate_exports()
diff --git a/reclass/datatypes/tests/test_exports.py b/reclass/datatypes/tests/test_exports.py
index 68fba6c..33eccbe 100644
--- a/reclass/datatypes/tests/test_exports.py
+++ b/reclass/datatypes/tests/test_exports.py
@@ -4,14 +4,17 @@
 # This file is part of reclass (http://github.com/madduck/reclass)
 #
 
+from reclass.settings import Settings
 from reclass.datatypes import Exports, Parameters
 from reclass.errors import ParseError
 import unittest
 
+SETTINGS = Settings()
+
 class TestInvQuery(unittest.TestCase):
 
     def test_overwrite_method(self):
-        e = Exports({'alpha': { 'one': 1, 'two': 2}})
+        e = Exports({'alpha': { 'one': 1, 'two': 2}}, SETTINGS, '')
         d = {'alpha': { 'three': 3, 'four': 4}}
         e.overwrite(d)
         e.initialise_interpolation()
@@ -19,77 +22,77 @@
 
     def test_malformed_invquery(self):
         with self.assertRaises(ParseError):
-            p = Parameters({'exp': '$[ exports:a exports:b == self:test_value ]'})
+            p = Parameters({'exp': '$[ exports:a exports:b == self:test_value ]'}, SETTINGS, '')
         with self.assertRaises(ParseError):
-            p = Parameters({'exp': '$[ exports:a if exports:b self:test_value ]'})
+            p = Parameters({'exp': '$[ exports:a if exports:b self:test_value ]'}, SETTINGS, '')
         with self.assertRaises(ParseError):
-            p = Parameters({'exp': '$[ exports:a if exports:b == ]'})
+            p = Parameters({'exp': '$[ exports:a if exports:b == ]'}, SETTINGS, '')
         with self.assertRaises(ParseError):
-            p = Parameters({'exp': '$[ exports:a if exports:b == self:test_value and exports:c = self:test_value2 ]'})
+            p = Parameters({'exp': '$[ exports:a if exports:b == self:test_value and exports:c = self:test_value2 ]'}, SETTINGS, '')
         with self.assertRaises(ParseError):
-            p = Parameters({'exp': '$[ exports:a if exports:b == self:test_value or exports:c == ]'})
+            p = Parameters({'exp': '$[ exports:a if exports:b == self:test_value or exports:c == ]'}, SETTINGS, '')
         with self.assertRaises(ParseError):
-            p = Parameters({'exp': '$[ exports:a if exports:b == self:test_value anddd exports:c == self:test_value2 ]'})
+            p = Parameters({'exp': '$[ exports:a if exports:b == self:test_value anddd exports:c == self:test_value2 ]'}, SETTINGS, '')
 
     def test_value_expr_invquery(self):
         e = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
-        p = Parameters({'exp': '$[ exports:a ]'})
+        p = Parameters({'exp': '$[ exports:a ]'}, SETTINGS, '')
         r = {'exp': {'node1': 1, 'node2': 3}}
         p.interpolate(e)
         self.assertEqual(p.as_dict(), r)
 
     def test_if_expr_invquery(self):
         e = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 4}}
-        p = Parameters({'exp': '$[ exports:a if exports:b == 4 ]'})
+        p = Parameters({'exp': '$[ exports:a if exports:b == 4 ]'}, SETTINGS, '')
         r = {'exp': {'node2': 3}}
         p.interpolate(e)
         self.assertEqual(p.as_dict(), r)
 
     def test_if_expr_invquery_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})
+        p = Parameters({'exp': '$[ exports:a if exports:b == self:test_value ]', 'test_value': 2}, SETTINGS, '')
         r = {'exp': {'node1': 1}, 'test_value': 2}
         p.interpolate(e)
         self.assertEqual(p.as_dict(), r)
 
     def test_list_if_expr_invquery(self):
         e = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 3}, 'node3': {'a': 3, 'b': 2}}
-        p = Parameters({'exp': '$[ if exports:b == 2 ]'})
+        p = Parameters({'exp': '$[ if exports:b == 2 ]'}, SETTINGS, '')
         r = {'exp': ['node1', 'node3']}
         p.interpolate(e)
         self.assertEqual(p.as_dict(), r)
 
     def test_if_expr_invquery_wth_and(self):
         e = {'node1': {'a': 1, 'b': 4, 'c': False}, 'node2': {'a': 3, 'b': 4, 'c': True}}
-        p = Parameters({'exp': '$[ exports:a if exports:b == 4 and exports:c == True ]'})
+        p = Parameters({'exp': '$[ exports:a if exports:b == 4 and exports:c == True ]'}, SETTINGS, '')
         r = {'exp': {'node2': 3}}
         p.interpolate(e)
         self.assertEqual(p.as_dict(), r)
 
     def test_if_expr_invquery_wth_or(self):
         e = {'node1': {'a': 1, 'b': 4}, 'node2': {'a': 3, 'b': 3}}
-        p = Parameters({'exp': '$[ exports:a if exports:b == 4 or exports:b == 3 ]'})
+        p = Parameters({'exp': '$[ exports:a if exports:b == 4 or exports:b == 3 ]'}, SETTINGS, '')
         r = {'exp': {'node1': 1, 'node2': 3}}
         p.interpolate(e)
         self.assertEqual(p.as_dict(), r)
 
     def test_list_if_expr_invquery_with_and(self):
         e = {'node1': {'a': 1, 'b': 2, 'c': 'green'}, 'node2': {'a': 3, 'b': 3}, 'node3': {'a': 3, 'b': 2, 'c': 'red'}}
-        p = Parameters({'exp': '$[ if exports:b == 2 and exports:c == green ]'})
+        p = Parameters({'exp': '$[ if exports:b == 2 and exports:c == green ]'}, SETTINGS, '')
         r = {'exp': ['node1']}
         p.interpolate(e)
         self.assertEqual(p.as_dict(), r)
 
     def test_list_if_expr_invquery_with_and_missing(self):
         e = {'node1': {'a': 1, 'b': 2, 'c': 'green'}, 'node2': {'a': 3, 'b': 3}, 'node3': {'a': 3, 'b': 2}}
-        p = Parameters({'exp': '$[ if exports:b == 2 and exports:c == green ]'})
+        p = Parameters({'exp': '$[ if exports:b == 2 and exports:c == green ]'}, SETTINGS, '')
         r = {'exp': ['node1']}
         p.interpolate(e)
         self.assertEqual(p.as_dict(), r)
 
     def test_list_if_expr_invquery_with_and(self):
         e = {'node1': {'a': 1, 'b': 2}, 'node2': {'a': 3, 'b': 3}, 'node3': {'a': 3, 'b': 4}}
-        p = Parameters({'exp': '$[ if exports:b == 2 or exports:b == 4 ]'})
+        p = Parameters({'exp': '$[ if exports:b == 2 or exports:b == 4 ]'}, SETTINGS, '')
         r = {'exp': ['node1', 'node3']}
         p.interpolate(e)
         self.assertEqual(p.as_dict(), r)
diff --git a/reclass/datatypes/tests/test_parameters.py b/reclass/datatypes/tests/test_parameters.py
index 2543ba9..a56ba65 100644
--- a/reclass/datatypes/tests/test_parameters.py
+++ b/reclass/datatypes/tests/test_parameters.py
@@ -6,10 +6,10 @@
 # Copyright © 2007–14 martin f. krafft <madduck@madduck.net>
 # Released under the terms of the Artistic Licence 2.0
 #
+
+from reclass.settings import Settings
 from reclass.datatypes import Parameters
-from reclass.defaults import REFERENCE_SENTINELS, ESCAPE_CHARACTER
 from reclass.errors import InfiniteRecursionError, InterpolationError
-from reclass.values.mergeoptions import MergeOptions
 import unittest
 try:
     import unittest.mock as mock
@@ -17,11 +17,12 @@
     import mock
 
 SIMPLE = {'one': 1, 'two': 2, 'three': 3}
+SETTINGS = Settings()
 
 class TestParameters(unittest.TestCase):
 
-    def _construct_mocked_params(self, iterable=None, delimiter=None):
-        p = Parameters(iterable, delimiter=delimiter)
+    def _construct_mocked_params(self, iterable=None, settings=SETTINGS):
+        p = Parameters(iterable, settings, '')
         self._base = base = p._base
         p._base = mock.MagicMock(spec_set=dict, wraps=base)
         p._base.__repr__ = mock.MagicMock(autospec=dict.__repr__,
@@ -47,22 +48,13 @@
     def test_repr_empty(self):
         p, b = self._construct_mocked_params()
         b.__repr__.return_value = repr({})
-        self.assertEqual('%r' % p, '%s(%r, %r)' % (p.__class__.__name__, {},
-                                                   Parameters.DEFAULT_PATH_DELIMITER))
+        self.assertEqual('%r' % p, '%s(%r)' % (p.__class__.__name__, {}))
         b.__repr__.assert_called_once_with()
 
     def test_repr(self):
         p, b = self._construct_mocked_params(SIMPLE)
         b.__repr__.return_value = repr(SIMPLE)
-        self.assertEqual('%r' % p, '%s(%r, %r)' % (p.__class__.__name__, SIMPLE,
-                                                   Parameters.DEFAULT_PATH_DELIMITER))
-        b.__repr__.assert_called_once_with()
-
-    def test_repr_delimiter(self):
-        delim = '%'
-        p, b = self._construct_mocked_params(SIMPLE, delim)
-        b.__repr__.return_value = repr(SIMPLE)
-        self.assertEqual('%r' % p, '%s(%r, %r)' % (p.__class__.__name__, SIMPLE, delim))
+        self.assertEqual('%r' % p, '%s(%r)' % (p.__class__.__name__, SIMPLE))
         b.__repr__.assert_called_once_with()
 
     def test_equal_empty(self):
@@ -74,8 +66,7 @@
 
     def test_equal_default_delimiter(self):
         p1, b1 = self._construct_mocked_params(SIMPLE)
-        p2, b2 = self._construct_mocked_params(SIMPLE,
-                                        Parameters.DEFAULT_PATH_DELIMITER)
+        p2, b2 = self._construct_mocked_params(SIMPLE, SETTINGS)
         b1.__eq__.return_value = True
         self.assertEqual(p1, p2)
         b1.__eq__.assert_called_once_with(b2)
@@ -95,8 +86,10 @@
         b1.__eq__.assert_called_once_with(b2)
 
     def test_unequal_delimiter(self):
-        p1, b1 = self._construct_mocked_params(delimiter=':')
-        p2, b2 = self._construct_mocked_params(delimiter='%')
+        settings1 = Settings({'delimiter': ':'})
+        settings2 = Settings({'delimiter': '%'})
+        p1, b1 = self._construct_mocked_params(settings=settings1)
+        p2, b2 = self._construct_mocked_params(settings=settings2)
         b1.__eq__.return_value = False
         self.assertNotEqual(p1, p2)
         b1.__eq__.assert_called_once_with(b2)
@@ -133,8 +126,8 @@
             self.assertIn(mock.call(key, value), b1.__setitem__.call_args_list)
 
     def test_stray_occurrence_overwrites_during_interpolation(self):
-        p1 = Parameters({'r' : mock.sentinel.ref, 'b': '${r}'})
-        p2 = Parameters({'b' : mock.sentinel.goal})
+        p1 = Parameters({'r' : mock.sentinel.ref, 'b': '${r}'}, SETTINGS, '')
+        p2 = Parameters({'b' : mock.sentinel.goal}, SETTINGS, '')
         p1.merge(p2)
         p1.interpolate()
         self.assertEqual(p1.as_dict()['b'], mock.sentinel.goal)
@@ -143,7 +136,7 @@
 class TestParametersNoMock(unittest.TestCase):
 
     def test_merge_scalars(self):
-        p = Parameters(SIMPLE)
+        p = Parameters(SIMPLE, SETTINGS, '')
         mergee = {'five':5,'four':4,'None':None,'tuple':(1,2,3)}
         p.merge(mergee)
         p.initialise_interpolation()
@@ -152,7 +145,7 @@
         self.assertDictEqual(p.as_dict(), goal)
 
     def test_merge_scalars_overwrite(self):
-        p = Parameters(SIMPLE)
+        p = Parameters(SIMPLE, SETTINGS, '')
         mergee = {'two':5,'four':4,'three':None,'one':(1,2,3)}
         p.merge(mergee)
         p.initialise_interpolation()
@@ -163,34 +156,35 @@
     def test_merge_lists(self):
         l1 = [1,2,3]
         l2 = [2,3,4]
-        p1 = Parameters(dict(list=l1[:]))
-        p2 = Parameters(dict(list=l2))
+        p1 = Parameters(dict(list=l1[:]), SETTINGS, '')
+        p2 = Parameters(dict(list=l2), SETTINGS, '')
         p1.merge(p2)
         p1.initialise_interpolation()
         self.assertListEqual(p1.as_dict()['list'], l1+l2)
 
     def test_merge_list_into_scalar(self):
+        settings = Settings({'allow_list_over_scalar': True})
         l = ['foo', 1, 2]
-        options = MergeOptions()
-        options.allow_list_over_scalar = True
-        p1 = Parameters(dict(key=l[0]), options=options)
-        p1.merge(Parameters(dict(key=l[1:])))
+        p1 = Parameters(dict(key=l[0]), settings, '')
+        p2 = Parameters(dict(key=l[1:]), settings, '')
+        p1.merge(p2)
         p1.initialise_interpolation()
         self.assertListEqual(p1.as_dict()['key'], l)
 
     def test_merge_scalar_over_list(self):
         l = ['foo', 1, 2]
-        options = MergeOptions()
-        options.allow_scalar_over_list = True
-        p1 = Parameters(dict(key=l[:2]), options=options)
-        p1.merge(Parameters(dict(key=l[2])))
+        settings = Settings({'allow_scalar_over_list': True})
+        p1 = Parameters(dict(key=l[:2]), settings, '')
+        p2 = Parameters(dict(key=l[2]), settings, '')
+        p1.merge(p2)
         p1.initialise_interpolation()
         self.assertEqual(p1.as_dict()['key'], l[2])
 
     def test_merge_dicts(self):
         mergee = {'five':5,'four':4,'None':None,'tuple':(1,2,3)}
-        p = Parameters(dict(dict=SIMPLE))
-        p.merge(Parameters(dict(dict=mergee)))
+        p = Parameters(dict(dict=SIMPLE), SETTINGS, '')
+        p2 = Parameters(dict(dict=mergee), SETTINGS, '')
+        p.merge(p2)
         p.initialise_interpolation()
         goal = SIMPLE.copy()
         goal.update(mergee)
@@ -198,8 +192,9 @@
 
     def test_merge_dicts_overwrite(self):
         mergee = {'two':5,'four':4,'three':None,'one':(1,2,3)}
-        p = Parameters(dict(dict=SIMPLE))
-        p.merge(Parameters(dict(dict=mergee)))
+        p = Parameters(dict(dict=SIMPLE), SETTINGS, '')
+        p2 = Parameters(dict(dict=mergee), SETTINGS, '')
+        p.merge(p2)
         p.initialise_interpolation()
         goal = SIMPLE.copy()
         goal.update(mergee)
@@ -213,94 +208,96 @@
                 'two': ['delta']}
         goal = {'one': {'a': 'alpha'},
                 'two': ['gamma']}
-        p = Parameters(dict(dict=base))
-        p.merge(Parameters(dict(dict=mergee)))
+        p = Parameters(dict(dict=base), SETTINGS, '')
+        p2 = Parameters(dict(dict=mergee), SETTINGS, '')
+        p.merge(p2)
         p.initialise_interpolation()
         self.assertDictEqual(p.as_dict(), dict(dict=goal))
 
     def test_merge_dict_into_scalar(self):
-        p = Parameters(dict(base='foo'))
+        p = Parameters(dict(base='foo'), SETTINGS, '')
+        p2 = Parameters(dict(base=SIMPLE), SETTINGS, '')
         with self.assertRaises(TypeError):
-            p.merge(Parameters(dict(base=SIMPLE)))
+            p.merge(p2)
             p.interpolate()
 
     def test_merge_scalar_over_dict(self):
-        options = MergeOptions()
-        options.allow_scalar_over_dict = True
-        p = Parameters(dict(base=SIMPLE), options=options)
+        settings = Settings({'allow_scalar_over_dict': True})
+        p = Parameters(dict(base=SIMPLE), settings, '')
         mergee = {'base':'foo'}
-        p.merge(Parameters(mergee))
+        p2 = Parameters(mergee, settings, '')
+        p.merge(p2)
         p.initialise_interpolation()
         self.assertDictEqual(p.as_dict(), mergee)
 
     def test_interpolate_single(self):
         v = 42
-        d = {'foo': 'bar'.join(REFERENCE_SENTINELS),
+        d = {'foo': 'bar'.join(SETTINGS.reference_sentinels),
              'bar': v}
-        p = Parameters(d)
+        p = Parameters(d, SETTINGS, '')
         p.interpolate()
         self.assertEqual(p.as_dict()['foo'], v)
 
     def test_interpolate_multiple(self):
         v = '42'
-        d = {'foo': 'bar'.join(REFERENCE_SENTINELS) + 'meep'.join(REFERENCE_SENTINELS),
+        d = {'foo': 'bar'.join(SETTINGS.reference_sentinels) + 'meep'.join(SETTINGS.reference_sentinels),
              'bar': v[0],
              'meep': v[1]}
-        p = Parameters(d)
+        p = Parameters(d, SETTINGS, '')
         p.interpolate()
         self.assertEqual(p.as_dict()['foo'], v)
 
     def test_interpolate_multilevel(self):
         v = 42
-        d = {'foo': 'bar'.join(REFERENCE_SENTINELS),
-             'bar': 'meep'.join(REFERENCE_SENTINELS),
+        d = {'foo': 'bar'.join(SETTINGS.reference_sentinels),
+             'bar': 'meep'.join(SETTINGS.reference_sentinels),
              'meep': v}
-        p = Parameters(d)
+        p = Parameters(d, SETTINGS, '')
         p.interpolate()
         self.assertEqual(p.as_dict()['foo'], v)
 
     def test_interpolate_list(self):
         l = [41,42,43]
-        d = {'foo': 'bar'.join(REFERENCE_SENTINELS),
+        d = {'foo': 'bar'.join(SETTINGS.reference_sentinels),
              'bar': l}
-        p = Parameters(d)
+        p = Parameters(d, SETTINGS, '')
         p.interpolate()
         self.assertEqual(p.as_dict()['foo'], l)
 
     def test_interpolate_infrecursion(self):
         v = 42
-        d = {'foo': 'bar'.join(REFERENCE_SENTINELS),
-             'bar': 'foo'.join(REFERENCE_SENTINELS)}
-        p = Parameters(d)
+        d = {'foo': 'bar'.join(SETTINGS.reference_sentinels),
+             'bar': 'foo'.join(SETTINGS.reference_sentinels)}
+        p = Parameters(d, SETTINGS, '')
         with self.assertRaises(InfiniteRecursionError):
             p.interpolate()
 
     def test_nested_references(self):
         d = {'a': '${${z}}', 'b': 2, 'z': 'b'}
         r = {'a': 2, 'b': 2, 'z': 'b'}
-        p = Parameters(d)
+        p = Parameters(d, SETTINGS, '')
         p.interpolate()
         self.assertEqual(p.as_dict(), r)
 
     def test_nested_deep_references(self):
         d = {'one': { 'a': 1, 'b': '${one:${one:c}}', 'c': 'a' } }
         r = {'one': { 'a': 1, 'b': 1, 'c': 'a'} }
-        p = Parameters(d)
+        p = Parameters(d, SETTINGS, '')
         p.interpolate()
         self.assertEqual(p.as_dict(), r)
 
     def test_stray_occurrence_overwrites_during_interpolation(self):
-        p1 = Parameters({'r' : 1, 'b': '${r}'})
-        p2 = Parameters({'b' : 2})
+        p1 = Parameters({'r' : 1, 'b': '${r}'}, SETTINGS, '')
+        p2 = Parameters({'b' : 2}, SETTINGS, '')
         p1.merge(p2)
         p1.interpolate()
         self.assertEqual(p1.as_dict()['b'], 2)
 
     def test_referenced_dict_deep_overwrite(self):
-        p1 = Parameters({'alpha': {'one': {'a': 1, 'b': 2} } })
-        p2 = Parameters({'beta': '${alpha}'})
+        p1 = Parameters({'alpha': {'one': {'a': 1, 'b': 2} } }, SETTINGS, '')
+        p2 = Parameters({'beta': '${alpha}'}, SETTINGS, '')
         p3 = Parameters({'alpha': {'one': {'c': 3, 'd': 4} },
-                         'beta':  {'one': {'a': 99} } })
+                         'beta':  {'one': {'a': 99} } }, SETTINGS, '')
         r = {'alpha': {'one': {'a':1, 'b': 2, 'c': 3, 'd':4} },
              'beta': {'one': {'a':99, 'b': 2, 'c': 3, 'd':4} } }
         p1.merge(p2)
@@ -309,8 +306,8 @@
         self.assertEqual(p1.as_dict(), r)
 
     def test_complex_reference_overwriting(self):
-        p1 = Parameters({'one': 'abc_123_${two}_${three}', 'two': 'XYZ', 'four': 4})
-        p2 = Parameters({'one': 'QWERTY_${three}_${four}', 'three': '999'})
+        p1 = Parameters({'one': 'abc_123_${two}_${three}', 'two': 'XYZ', 'four': 4}, SETTINGS, '')
+        p2 = Parameters({'one': 'QWERTY_${three}_${four}', 'three': '999'}, SETTINGS, '')
         r = {'one': 'QWERTY_999_4', 'two': 'XYZ', 'three': '999', 'four': 4}
         p1.merge(p2)
         p1.interpolate()
@@ -318,56 +315,56 @@
 
     def test_nested_reference_with_overwriting(self):
         p1 = Parameters({'one': {'a': 1, 'b': 2, 'z': 'a'},
-                         'two': '${one:${one:z}}' })
-        p2 = Parameters({'one': {'z': 'b'} })
+                         'two': '${one:${one:z}}' }, SETTINGS, '')
+        p2 = Parameters({'one': {'z': 'b'} }, SETTINGS, '')
         r = {'one': {'a': 1, 'b':2, 'z': 'b'}, 'two': 2}
         p1.merge(p2)
         p1.interpolate()
         self.assertEqual(p1.as_dict(), r)
 
     def test_merge_referenced_lists(self):
-        p1 = Parameters({'one': [ 1, 2, 3 ], 'two': [ 4, 5, 6 ], 'three': '${one}'})
-        p2 = Parameters({'three': '${two}'})
+        p1 = Parameters({'one': [ 1, 2, 3 ], 'two': [ 4, 5, 6 ], 'three': '${one}'}, SETTINGS, '')
+        p2 = Parameters({'three': '${two}'}, SETTINGS, '')
         r = {'one': [ 1, 2, 3 ], 'two': [ 4, 5, 6], 'three': [ 1, 2, 3, 4, 5, 6 ]}
         p1.merge(p2)
         p1.interpolate()
         self.assertEqual(p1.as_dict(), r)
 
     def test_merge_referenced_dicts(self):
-        p1 = Parameters({'one': {'a': 1, 'b': 2}, 'two': {'c': 3, 'd': 4}, 'three': '${one}'})
-        p2 = Parameters({'three': '${two}'})
+        p1 = Parameters({'one': {'a': 1, 'b': 2}, 'two': {'c': 3, 'd': 4}, 'three': '${one}'}, SETTINGS, '')
+        p2 = Parameters({'three': '${two}'}, SETTINGS, '')
         r = {'one': {'a': 1, 'b': 2}, 'two': {'c': 3, 'd': 4}, 'three': {'a': 1, 'b': 2, 'c': 3, 'd': 4}}
         p1.merge(p2)
         p1.interpolate()
         self.assertEqual(p1.as_dict(), r)
 
     def test_deep_refs_in_referenced_dicts(self):
-        p = Parameters({'A': '${C:a}', 'B': {'a': 1, 'b': 2}, 'C': '${B}'})
+        p = Parameters({'A': '${C:a}', 'B': {'a': 1, 'b': 2}, 'C': '${B}'}, SETTINGS, '')
         r = {'A': 1, 'B': {'a': 1, 'b': 2}, 'C': {'a': 1, 'b': 2}}
         p.interpolate()
         self.assertEqual(p.as_dict(), r)
 
     def test_overwrite_none(self):
-        p1 = Parameters({'A': None, 'B': None, 'C': None, 'D': None, 'E': None, 'F': None})
-        p2 = Parameters({'A': 'abc', 'B': [1, 2, 3], 'C': {'a': 'aaa', 'b': 'bbb'}, 'D': '${A}', 'E': '${B}', 'F': '${C}'})
+        p1 = Parameters({'A': None, 'B': None, 'C': None, 'D': None, 'E': None, 'F': None}, SETTINGS, '')
+        p2 = Parameters({'A': 'abc', 'B': [1, 2, 3], 'C': {'a': 'aaa', 'b': 'bbb'}, 'D': '${A}', 'E': '${B}', 'F': '${C}'}, SETTINGS, '')
         r = {'A': 'abc', 'B': [1, 2, 3], 'C': {'a': 'aaa', 'b': 'bbb'}, 'D': 'abc', 'E': [1, 2, 3], 'F': {'a': 'aaa', 'b': 'bbb'}}
         p1.merge(p2)
         p1.interpolate()
         self.assertEqual(p1.as_dict(), r)
 
     def test_interpolate_escaping(self):
-        v = 'bar'.join(REFERENCE_SENTINELS)
-        d = {'foo': ESCAPE_CHARACTER + 'bar'.join(REFERENCE_SENTINELS),
+        v = 'bar'.join(SETTINGS.reference_sentinels)
+        d = {'foo': SETTINGS.escape_character + 'bar'.join(SETTINGS.reference_sentinels),
              'bar': 'unused'}
-        p = Parameters(d)
+        p = Parameters(d, SETTINGS, '')
         p.initialise_interpolation()
         self.assertEqual(p.as_dict()['foo'], v)
 
     def test_interpolate_double_escaping(self):
-        v = ESCAPE_CHARACTER + 'meep'
-        d = {'foo': ESCAPE_CHARACTER + ESCAPE_CHARACTER + 'bar'.join(REFERENCE_SENTINELS),
+        v = SETTINGS.escape_character + 'meep'
+        d = {'foo': SETTINGS.escape_character + SETTINGS.escape_character + 'bar'.join(SETTINGS.reference_sentinels),
              'bar': 'meep'}
-        p = Parameters(d)
+        p = Parameters(d, SETTINGS, '')
         p.interpolate()
         self.assertEqual(p.as_dict()['foo'], v)
 
@@ -376,43 +373,43 @@
         needs to be printed as-is, to ensure backwards compatibility to older versions."""
         v = ' '.join([
             # Escape character followed by unescapable character
-            '1', ESCAPE_CHARACTER,
+            '1', SETTINGS.escape_character,
             # Escape character followed by escape character
-            '2', ESCAPE_CHARACTER + ESCAPE_CHARACTER,
+            '2', SETTINGS.escape_character + SETTINGS.escape_character,
             # Escape character followed by interpolation end sentinel
-            '3', ESCAPE_CHARACTER + REFERENCE_SENTINELS[1],
+            '3', SETTINGS.escape_character + SETTINGS.reference_sentinels[1],
             # Escape character at the end of the string
-            '4', ESCAPE_CHARACTER
+            '4', SETTINGS.escape_character
             ])
         d = {'foo': v}
-        p = Parameters(d)
+        p = Parameters(d, SETTINGS, '')
         p.initialise_interpolation()
         self.assertEqual(p.as_dict()['foo'], v)
 
     def test_escape_close_in_ref(self):
-        p1 = Parameters({'one}': 1, 'two': '${one\\}}'})
+        p1 = Parameters({'one}': 1, 'two': '${one\\}}'}, SETTINGS, '')
         r = {'one}': 1, 'two': 1}
         p1.interpolate()
         self.assertEqual(p1.as_dict(), r)
 
     def test_double_escape_in_ref(self):
         d = {'one\\': 1, 'two': '${one\\\\}'}
-        p1 = Parameters(d)
+        p1 = Parameters(d, SETTINGS, '')
         r = {'one\\': 1, 'two': 1}
         p1.interpolate()
         self.assertEqual(p1.as_dict(), r)
 
     def test_merging_for_multiple_nodes(self):
-        p1 = Parameters({ 'alpha': { 'one': 111 }})
-        p2 = Parameters({ 'beta': {'two': '${alpha:one}' }})
-        p3 = Parameters({ 'beta': {'two': 222 }})
-        n1 = Parameters({ 'name': 'node1'})
+        p1 = Parameters({ 'alpha': { 'one': 111 }}, SETTINGS, '')
+        p2 = Parameters({ 'beta': {'two': '${alpha:one}' }}, SETTINGS, '')
+        p3 = Parameters({ 'beta': {'two': 222 }}, SETTINGS, '')
+        n1 = Parameters({ 'name': 'node1'}, SETTINGS, '')
         r1 = { 'alpha': { 'one': 111 }, 'beta': { 'two': 111 }, 'name': 'node1' }
         r2 = { 'alpha': { 'one': 111 }, 'beta': { 'two': 222 }, 'name': 'node2' }
         n1.merge(p1)
         n1.merge(p2)
         n1.interpolate()
-        n2 = Parameters({'name': 'node2'})
+        n2 = Parameters({'name': 'node2'}, SETTINGS, '')
         n2.merge(p1)
         n2.merge(p2)
         n2.merge(p3)
@@ -421,16 +418,16 @@
         self.assertEqual(n2.as_dict(), r2)
 
     def test_list_merging_for_multiple_nodes(self):
-        p1 = Parameters({ 'alpha': { 'one': [1, 2] }})
-        p2 = Parameters({ 'beta': {'two': '${alpha:one}' }})
-        p3 = Parameters({ 'beta': {'two': [3] }})
-        n1 = Parameters({ 'name': 'node1'})
+        p1 = Parameters({ 'alpha': { 'one': [1, 2] }}, SETTINGS, '')
+        p2 = Parameters({ 'beta': {'two': '${alpha:one}' }}, SETTINGS, '')
+        p3 = Parameters({ 'beta': {'two': [3] }}, SETTINGS, '')
+        n1 = Parameters({ 'name': 'node1'}, SETTINGS, '')
         r1 = { 'alpha': { 'one': [1, 2] }, 'beta': { 'two': [1, 2] }, 'name': 'node1' }
         r2 = { 'alpha': { 'one': [1, 2] }, 'beta': { 'two': [1, 2, 3] }, 'name': 'node2' }
         n1.merge(p1)
         n1.merge(p2)
         n1.interpolate()
-        n2 = Parameters({'name': 'node2'})
+        n2 = Parameters({'name': 'node2'}, SETTINGS, '')
         n2.merge(p1)
         n2.merge(p2)
         n2.merge(p3)
@@ -439,16 +436,16 @@
         self.assertEqual(n2.as_dict(), r2)
 
     def test_dict_merging_for_multiple_nodes(self):
-        p1 = Parameters({ 'alpha': { 'one': { 'a': 'aa', 'b': 'bb' }}})
-        p2 = Parameters({ 'beta': {'two': '${alpha:one}' }})
-        p3 = Parameters({ 'beta': {'two': {'c': 'cc' }}})
-        n1 = Parameters({ 'name': 'node1'})
+        p1 = Parameters({ 'alpha': { 'one': { 'a': 'aa', 'b': 'bb' }}}, SETTINGS, '')
+        p2 = Parameters({ 'beta': {'two': '${alpha:one}' }}, SETTINGS, '')
+        p3 = Parameters({ 'beta': {'two': {'c': 'cc' }}}, SETTINGS, '')
+        n1 = Parameters({ 'name': 'node1'}, SETTINGS, '')
         r1 = { 'alpha': { 'one': {'a': 'aa', 'b': 'bb'} }, 'beta': { 'two': {'a': 'aa', 'b': 'bb'} }, 'name': 'node1' }
         r2 = { 'alpha': { 'one': {'a': 'aa', 'b': 'bb'} }, 'beta': { 'two': {'a': 'aa', 'b': 'bb', 'c': 'cc'} }, 'name': 'node2' }
         n1.merge(p1)
         n1.merge(p2)
         n1.interpolate()
-        n2 = Parameters({'name': 'node2'})
+        n2 = Parameters({'name': 'node2'}, SETTINGS, '')
         n2.merge(p1)
         n2.merge(p2)
         n2.merge(p3)
@@ -457,14 +454,14 @@
         self.assertEqual(n2.as_dict(), r2)
 
     def test_list_merging_with_refs_for_multiple_nodes(self):
-        p1 = Parameters({ 'alpha': { 'one': [1, 2], 'two': [3, 4] }})
-        p2 = Parameters({ 'beta': { 'three': '${alpha:one}' }})
-        p3 = Parameters({ 'beta': { 'three': '${alpha:two}' }})
-        p4 = Parameters({ 'beta': { 'three': '${alpha:one}' }})
-        n1 = Parameters({ 'name': 'node1' })
+        p1 = Parameters({ 'alpha': { 'one': [1, 2], 'two': [3, 4] }}, SETTINGS, '')
+        p2 = Parameters({ 'beta': { 'three': '${alpha:one}' }}, SETTINGS, '')
+        p3 = Parameters({ 'beta': { 'three': '${alpha:two}' }}, SETTINGS, '')
+        p4 = Parameters({ 'beta': { 'three': '${alpha:one}' }}, SETTINGS, '')
+        n1 = Parameters({ 'name': 'node1' }, SETTINGS, '')
         r1 = {'alpha': {'one': [1, 2], 'two': [3, 4]}, 'beta': {'three': [1, 2]}, 'name': 'node1'}
         r2 = {'alpha': {'one': [1, 2], 'two': [3, 4]}, 'beta': {'three': [1, 2, 3, 4, 1, 2]}, 'name': 'node2'}
-        n2 = Parameters({ 'name': 'node2' })
+        n2 = Parameters({ 'name': 'node2' }, SETTINGS, '')
         n2.merge(p1)
         n2.merge(p2)
         n2.merge(p3)
@@ -477,18 +474,18 @@
         self.assertEqual(n2.as_dict(), r2)
 
     def test_nested_refs_with_multiple_nodes(self):
-        p1 = Parameters({ 'alpha': { 'one': 1, 'two': 2 } })
-        p2 = Parameters({ 'beta': { 'three': 'one' } })
-        p3 = Parameters({ 'beta': { 'three': 'two' } })
-        p4 = Parameters({ 'beta': { 'four': '${alpha:${beta:three}}' } })
-        n1 = Parameters({ 'name': 'node1' })
+        p1 = Parameters({ 'alpha': { 'one': 1, 'two': 2 } }, SETTINGS, '')
+        p2 = Parameters({ 'beta': { 'three': 'one' } }, SETTINGS, '')
+        p3 = Parameters({ 'beta': { 'three': 'two' } }, SETTINGS, '')
+        p4 = Parameters({ 'beta': { 'four': '${alpha:${beta:three}}' } }, SETTINGS, '')
+        n1 = Parameters({ 'name': 'node1' }, SETTINGS, '')
         r1 = {'alpha': {'one': 1, 'two': 2}, 'beta': {'three': 'one', 'four': 1}, 'name': 'node1'}
         r2 = {'alpha': {'one': 1, 'two': 2}, 'beta': {'three': 'two', 'four': 2}, 'name': 'node2'}
         n1.merge(p1)
         n1.merge(p4)
         n1.merge(p2)
         n1.interpolate()
-        n2 = Parameters({ 'name': 'node2' })
+        n2 = Parameters({ 'name': 'node2' }, SETTINGS, '')
         n2.merge(p1)
         n2.merge(p4)
         n2.merge(p3)
@@ -498,7 +495,7 @@
 
     def test_nested_refs_error_message(self):
         # beta is missing, oops
-        p1 = Parameters({'alpha': {'one': 1, 'two': 2}, 'gamma': '${alpha:${beta}}'})
+        p1 = Parameters({'alpha': {'one': 1, 'two': 2}, 'gamma': '${alpha:${beta}}'}, SETTINGS, '')
         with self.assertRaises(InterpolationError) as error:
             p1.interpolate()
         self.assertEqual(error.exception.message, "Bad references: ['beta'], for path: gamma")
diff --git a/reclass/defaults.py b/reclass/defaults.py
index 557d511..baac195 100644
--- a/reclass/defaults.py
+++ b/reclass/defaults.py
@@ -31,9 +31,12 @@
 PARAMETER_DICT_KEY_OVERRIDE_PREFIX = '~'
 ESCAPE_CHARACTER = '\\'
 
-MERGE_ALLOW_SCALAR_OVER_DICT = False
-MERGE_ALLOW_SCALAR_OVER_LIST = False
-MERGE_ALLOW_LIST_OVER_SCALAR = False
-MERGE_ALLOW_DICT_OVER_SCALAR = False
+ALLOW_SCALAR_OVER_DICT = False
+ALLOW_SCALAR_OVER_LIST = False
+ALLOW_LIST_OVER_SCALAR = False
+ALLOW_DICT_OVER_SCALAR = False
 
 AUTOMATIC_RECLASS_PARAMETERS = True
+IGNORE_CLASS_NOT_FOUND = False
+
+DEFAULT_ENVIRONMENT = 'base'
diff --git a/reclass/settings.py b/reclass/settings.py
new file mode 100644
index 0000000..4b5928f
--- /dev/null
+++ b/reclass/settings.py
@@ -0,0 +1,34 @@
+import reclass.defaults
+import reclass.values.parser_funcs
+
+class Settings(object):
+
+    def __init__(self, options={}):
+        self.allow_scalar_over_dict = options.get('allow_scalar_over_dict', reclass.defaults.ALLOW_SCALAR_OVER_DICT)
+        self.allow_scalar_over_list = options.get('allow_scalar_over_list', reclass.defaults.ALLOW_SCALAR_OVER_LIST)
+        self.allow_list_over_scalar = options.get('allow_list_over_scalar', reclass.defaults.ALLOW_LIST_OVER_SCALAR)
+        self.allow_dict_over_scalar = options.get('allow_dict_over_scalar', reclass.defaults.ALLOW_DICT_OVER_SCALAR)
+        self.automatic_parameters = options.get('automatic_parameters', reclass.defaults.AUTOMATIC_RECLASS_PARAMETERS)
+        self.default_environment = options.get('default_environment', reclass.defaults.DEFAULT_ENVIRONMENT)
+        self.delimiter = options.get('delimiter', reclass.defaults.PARAMETER_INTERPOLATION_DELIMITER)
+        self.dict_key_override_prefix = options.get('dict_key_override_prefix', reclass.defaults.PARAMETER_DICT_KEY_OVERRIDE_PREFIX)
+        self.escape_character = options.get('escape_character', reclass.defaults.ESCAPE_CHARACTER)
+        self.export_sentinels = options.get('export_sentinels', reclass.defaults.EXPORT_SENTINELS)
+        self.reference_sentinels = options.get('reference_sentinels', reclass.defaults.REFERENCE_SENTINELS)
+
+        self.ref_parser = reclass.values.parser_funcs.get_ref_parser(self.escape_character, self.reference_sentinels, self.export_sentinels)
+        self.simple_ref_parser = reclass.values.parser_funcs.get_simple_ref_parser(self.escape_character, self.reference_sentinels, self.export_sentinels)
+
+    def __eq__(self, other):
+        return isinstance(other, type(self)) \
+               and self.allow_scalar_over_dict == other.allow_scalar_over_dict \
+               and self.allow_scalar_over_list == other.allow_scalar_over_list \
+               and self.allow_list_over_scalar == other.allow_list_over_scalar \
+               and self.allow_dict_over_scalar == other.allow_dict_over_scalar \
+               and self.automatic_parameters == other.automatic_parameters \
+               and self.default_environment == other.default_environment \
+               and self.delimiter == other.delimiter \
+               and self.dict_key_override_prefix == other.dict_key_override_prefix \
+               and self.escape_character == other.escape_character \
+               and self.export_sentinels == other.export_sentinels \
+               and self.reference_sentinels == other.reference_sentinels
diff --git a/reclass/storage/__init__.py b/reclass/storage/__init__.py
index 3990b91..f49ac16 100644
--- a/reclass/storage/__init__.py
+++ b/reclass/storage/__init__.py
@@ -14,11 +14,11 @@
 
     name = property(lambda self: self._name)
 
-    def get_node(self, name, merge_base=None):
+    def get_node(self, name, settings):
         msg = "Storage class '{0}' does not implement node entity retrieval."
         raise NotImplementedError(msg.format(self.name))
 
-    def get_class(self, name):
+    def get_class(self, name, environment, settings):
         msg = "Storage class '{0}' does not implement class entity retrieval."
         raise NotImplementedError(msg.format(self.name))
 
diff --git a/reclass/storage/memcache_proxy.py b/reclass/storage/memcache_proxy.py
index 6c898a2..405ea8e 100644
--- a/reclass/storage/memcache_proxy.py
+++ b/reclass/storage/memcache_proxy.py
@@ -30,25 +30,25 @@
 
     name = property(lambda self: self._real_storage.name)
 
-    def get_node(self, name):
+    def get_node(self, name, settings):
         if not self._cache_nodes:
-            return self._real_storage.get_node(name)
+            return self._real_storage.get_node(name, settings)
         try:
             return self._nodes_cache[name]
         except KeyError, e:
-            ret = self._real_storage.get_node(name)
+            ret = self._real_storage.get_node(name, settings)
             self._nodes_cache[name] = ret
         return ret
 
-    def get_class(self, name, environment):
+    def get_class(self, name, environment, settings):
         if not self._cache_classes:
-            return self._real_storage.get_class(name, environment)
+            return self._real_storage.get_class(name, environment, settings)
         try:
             return self._classes_cache[environment][name]
         except KeyError, e:
             if environment not in self._classes_cache:
                 self._classes_cache[environment] = dict()
-            ret = self._real_storage.get_class(name, environment)
+            ret = self._real_storage.get_class(name, environment, settings)
             self._classes_cache[environment][name] = ret
         return ret
 
diff --git a/reclass/storage/mixed/__init__.py b/reclass/storage/mixed/__init__.py
index d9983fd..4651e00 100644
--- a/reclass/storage/mixed/__init__.py
+++ b/reclass/storage/mixed/__init__.py
@@ -47,12 +47,12 @@
             ret = ret['uri']
         return self.MixedUri(uri['storage_type'], ret)
 
-    def get_node(self, name):
-        return self._nodes_storage.get_node(name)
+    def get_node(self, name, settings):
+        return self._nodes_storage.get_node(name, settings)
 
-    def get_class(self, name, environment):
+    def get_class(self, name, environment, settings):
         storage = self._classes_storage.get(environment, self._classes_default_storage)
-        return storage.get_class(name, environment=environment)
+        return storage.get_class(name, environment, settings)
 
     def enumerate_nodes(self):
         return self._nodes_storage.enumerate_nodes()
diff --git a/reclass/storage/tests/test_memcache_proxy.py b/reclass/storage/tests/test_memcache_proxy.py
index 6764251..a47c29d 100644
--- a/reclass/storage/tests/test_memcache_proxy.py
+++ b/reclass/storage/tests/test_memcache_proxy.py
@@ -6,6 +6,8 @@
 # Copyright © 2007–14 martin f. krafft <madduck@madduck.net>
 # Released under the terms of the Artistic Licence 2.0
 #
+
+from reclass.settings import Settings
 from reclass.storage.memcache_proxy import MemcacheProxy
 from reclass.storage import NodeStorageBase
 
@@ -22,48 +24,48 @@
 
     def test_no_nodes_caching(self):
         p = MemcacheProxy(self._storage, cache_nodes=False)
-        NAME = 'foo'; NAME2 = 'bar'; RET = 'baz'
+        NAME = 'foo'; NAME2 = 'bar'; RET = 'baz'; SETTINGS = Settings()
         self._storage.get_node.return_value = RET
-        self.assertEqual(p.get_node(NAME), RET)
-        self.assertEqual(p.get_node(NAME), RET)
-        self.assertEqual(p.get_node(NAME2), RET)
-        self.assertEqual(p.get_node(NAME2), RET)
-        expected = [mock.call(NAME), mock.call(NAME),
-                    mock.call(NAME2), mock.call(NAME2)]
+        self.assertEqual(p.get_node(NAME, SETTINGS), RET)
+        self.assertEqual(p.get_node(NAME, SETTINGS), RET)
+        self.assertEqual(p.get_node(NAME2, SETTINGS), RET)
+        self.assertEqual(p.get_node(NAME2, SETTINGS), RET)
+        expected = [mock.call(NAME, SETTINGS), mock.call(NAME, SETTINGS),
+                    mock.call(NAME2, SETTINGS), mock.call(NAME2, SETTINGS)]
         self.assertListEqual(self._storage.get_node.call_args_list, expected)
 
     def test_nodes_caching(self):
         p = MemcacheProxy(self._storage, cache_nodes=True)
-        NAME = 'foo'; NAME2 = 'bar'; RET = 'baz'
+        NAME = 'foo'; NAME2 = 'bar'; RET = 'baz'; SETTINGS = Settings()
         self._storage.get_node.return_value = RET
-        self.assertEqual(p.get_node(NAME), RET)
-        self.assertEqual(p.get_node(NAME), RET)
-        self.assertEqual(p.get_node(NAME2), RET)
-        self.assertEqual(p.get_node(NAME2), RET)
-        expected = [mock.call(NAME), mock.call(NAME2)] # called once each
+        self.assertEqual(p.get_node(NAME, SETTINGS), RET)
+        self.assertEqual(p.get_node(NAME, SETTINGS), RET)
+        self.assertEqual(p.get_node(NAME2, SETTINGS), RET)
+        self.assertEqual(p.get_node(NAME2, SETTINGS), RET)
+        expected = [mock.call(NAME, SETTINGS), mock.call(NAME2, SETTINGS)] # called once each
         self.assertListEqual(self._storage.get_node.call_args_list, expected)
 
     def test_no_classes_caching(self):
         p = MemcacheProxy(self._storage, cache_classes=False)
-        NAME = 'foo'; NAME2 = 'bar'; RET = 'baz'
+        NAME = 'foo'; NAME2 = 'bar'; RET = 'baz'; SETTINGS = Settings()
         self._storage.get_class.return_value = RET
-        self.assertEqual(p.get_class(NAME, None), RET)
-        self.assertEqual(p.get_class(NAME, None), RET)
-        self.assertEqual(p.get_class(NAME2, None), RET)
-        self.assertEqual(p.get_class(NAME2, None), RET)
-        expected = [mock.call(NAME, None), mock.call(NAME, None),
-                    mock.call(NAME2, None), mock.call(NAME2, None)]
+        self.assertEqual(p.get_class(NAME, None, SETTINGS), RET)
+        self.assertEqual(p.get_class(NAME, None, SETTINGS), RET)
+        self.assertEqual(p.get_class(NAME2, None, SETTINGS), RET)
+        self.assertEqual(p.get_class(NAME2, None, SETTINGS), RET)
+        expected = [mock.call(NAME, None, SETTINGS), mock.call(NAME, None, SETTINGS),
+                    mock.call(NAME2, None, SETTINGS), mock.call(NAME2, None, SETTINGS)]
         self.assertListEqual(self._storage.get_class.call_args_list, expected)
 
     def test_classes_caching(self):
         p = MemcacheProxy(self._storage, cache_classes=True)
-        NAME = 'foo'; NAME2 = 'bar'; RET = 'baz'
+        NAME = 'foo'; NAME2 = 'bar'; RET = 'baz'; SETTINGS = Settings()
         self._storage.get_class.return_value = RET
-        self.assertEqual(p.get_class(NAME, None), RET)
-        self.assertEqual(p.get_class(NAME, None), RET)
-        self.assertEqual(p.get_class(NAME2, None), RET)
-        self.assertEqual(p.get_class(NAME2, None), RET)
-        expected = [mock.call(NAME, None), mock.call(NAME2, None)] # called once each
+        self.assertEqual(p.get_class(NAME, None, SETTINGS), RET)
+        self.assertEqual(p.get_class(NAME, None, SETTINGS), RET)
+        self.assertEqual(p.get_class(NAME2, None, SETTINGS), RET)
+        self.assertEqual(p.get_class(NAME2, None, SETTINGS), RET)
+        expected = [mock.call(NAME, None, SETTINGS), mock.call(NAME2, None, SETTINGS)] # called once each
         self.assertListEqual(self._storage.get_class.call_args_list, expected)
 
     def test_nodelist_no_caching(self):
diff --git a/reclass/storage/yaml_fs/__init__.py b/reclass/storage/yaml_fs/__init__.py
index 35e4f05..20388ac 100644
--- a/reclass/storage/yaml_fs/__init__.py
+++ b/reclass/storage/yaml_fs/__init__.py
@@ -87,7 +87,7 @@
         d.walk(register_fn)
         return ret
 
-    def get_node(self, name):
+    def get_node(self, name, settings):
         vvv('GET NODE {0}'.format(name))
         try:
             relpath = self._nodes[name]
@@ -95,16 +95,16 @@
             name = os.path.splitext(relpath)[0]
         except KeyError, e:
             raise reclass.errors.NodeNotFound(self.name, name, self.nodes_uri)
-        entity = YamlData.from_file(path).get_entity(name)
+        entity = YamlData.from_file(path).get_entity(name, settings)
         return entity
 
-    def get_class(self, name, environment):
+    def get_class(self, name, environment, setings):
         vvv('GET CLASS {0}'.format(name))
         try:
             path = os.path.join(self.classes_uri, self._classes[name])
         except KeyError, e:
             raise reclass.errors.ClassNotFound(self.name, name, self.classes_uri)
-        entity = YamlData.from_file(path).get_entity(name)
+        entity = YamlData.from_file(path).get_entity(name, settings)
         return entity
 
     def enumerate_nodes(self):
diff --git a/reclass/storage/yaml_git/__init__.py b/reclass/storage/yaml_git/__init__.py
index 3482423..94eca59 100644
--- a/reclass/storage/yaml_git/__init__.py
+++ b/reclass/storage/yaml_git/__init__.py
@@ -221,13 +221,13 @@
     nodes_uri = property(lambda self: self._nodes_uri)
     classes_uri = property(lambda self: self._classes_uri)
 
-    def get_node(self, name):
+    def get_node(self, name, settings):
         file = self._nodes[name]
         blob = self._repos[self._nodes_uri.repo].get(file.id)
-        entity = YamlData.from_string(blob.data, 'git_fs://{0} {1} {2}'.format(self._nodes_uri.repo, self._nodes_uri.branch, file.path)).get_entity(name)
+        entity = YamlData.from_string(blob.data, 'git_fs://{0} {1} {2}'.format(self._nodes_uri.repo, self._nodes_uri.branch, file.path)).get_entity(name, setings)
         return entity
 
-    def get_class(self, name, environment):
+    def get_class(self, name, environment, settings):
         uri = self._env_to_uri(environment)
         if uri.root is not None:
             name = '{0}.{1}'.format(uri.root, name)
@@ -239,7 +239,7 @@
             raise reclass.errors.NotFoundError("File " + name + " missing from " + uri.repo + " branch " + uri.branch)
         file = self._repos[uri.repo].files[uri.branch][name]
         blob = self._repos[uri.repo].get(file.id)
-        entity = YamlData.from_string(blob.data, 'git_fs://{0} {1} {2}'.format(uri.repo, uri.branch, file.path)).get_entity(name)
+        entity = YamlData.from_string(blob.data, 'git_fs://{0} {1} {2}'.format(uri.repo, uri.branch, file.path)).get_entity(name, settings)
         return entity
 
     def enumerate_nodes(self):
diff --git a/reclass/storage/yamldata.py b/reclass/storage/yamldata.py
index 31cc8ff..0dda2b7 100644
--- a/reclass/storage/yamldata.py
+++ b/reclass/storage/yamldata.py
@@ -47,9 +47,9 @@
     def get_data(self):
         return self._data
 
-    def get_entity(self, name=None):
-        if name is None:
-            name = self._uri
+    def get_entity(self, name, settings):
+        #if name is None:
+        #    name = self._uri
 
         classes = self._data.get('classes')
         if classes is None:
@@ -64,17 +64,17 @@
         parameters = self._data.get('parameters')
         if parameters is None:
             parameters = {}
-        parameters = datatypes.Parameters(parameters, uri=self._uri)
+        parameters = datatypes.Parameters(parameters, settings, self._uri)
 
         exports = self._data.get('exports')
         if exports is None:
             exports = {}
-        exports = datatypes.Exports(exports, uri=self._uri)
+        exports = datatypes.Exports(exports, settings, self._uri)
 
         env = self._data.get('environment', None)
 
-        return datatypes.Entity(classes, applications, parameters, exports,
-                                name=name, environment=env, uri=self.uri)
+        return datatypes.Entity(settings, classes=classes, applications=applications, parameters=parameters,
+                                exports=exports, name=name, environment=env, uri=self.uri)
 
     def __str__(self):
         return '<{0} {1}, {2}>'.format(self.__class__.__name__, self._uri,
diff --git a/reclass/values/compitem.py b/reclass/values/compitem.py
index ea342a5..5786934 100644
--- a/reclass/values/compitem.py
+++ b/reclass/values/compitem.py
@@ -4,13 +4,15 @@
 # This file is part of reclass
 #
 
+from reclass.settings import Settings
 from item import Item
 
 class CompItem(Item):
 
-    def __init__(self, items):
+    def __init__(self, items, settings):
         self.type = Item.COMPOSITE
         self._items = items
+        self._settings = settings
         self._refs = []
         self._allRefs = False
         self.assembleRefs()
diff --git a/reclass/values/dictitem.py b/reclass/values/dictitem.py
index bc58f67..d778fe2 100644
--- a/reclass/values/dictitem.py
+++ b/reclass/values/dictitem.py
@@ -4,13 +4,15 @@
 # This file is part of reclass
 #
 
+from reclass.settings import Settings
 from item import Item
 
 class DictItem(Item):
 
-    def __init__(self, item):
+    def __init__(self, item, settings):
         self.type = Item.DICTIONARY
         self._dict = item
+        self._settings = settings
 
     def contents(self):
         return self._dict
@@ -18,9 +20,9 @@
     def is_container(self):
         return True
 
-    def merge_over(self, item, options):
+    def merge_over(self, item):
         if item.type == Item.SCALAR:
-            if item.contents() is None or options.allow_dict_over_scalar:
+            if item.contents() is None or self._settings.allow_dict_over_scalar:
                 return self
             else:
                 raise TypeError('allow dict over scalar = False: cannot merge %s onto %s' % (repr(self), repr(item)))
diff --git a/reclass/values/invitem.py b/reclass/values/invitem.py
index 50eb388..024ef99 100644
--- a/reclass/values/invitem.py
+++ b/reclass/values/invitem.py
@@ -8,6 +8,7 @@
 import pyparsing as pp
 
 from item import Item
+from reclass.settings import Settings
 from reclass.utils.dictpath import DictPath
 from reclass.errors import ExpressionError, ParseError, ResolveError
 
@@ -195,9 +196,9 @@
 
     _parser = _get_parser()
 
-    def __init__(self, item, delimiter):
+    def __init__(self, item, settings):
         self.type = Item.INV_QUERY
-        self._delimiter = delimiter
+        self._settings = settings
         self._parse_expression(item.render(None, None))
 
     def _parse_expression(self, expr):
@@ -213,16 +214,16 @@
             raise ExpressionError('Failed to parse %s' % str(self._expr))
 
         if self._expr_type == _VALUE:
-            self._value_path = DictPath(self._delimiter, self._expr[0][1]).drop_first()
-            self._question = Question([], self._delimiter)
+            self._value_path = DictPath(self._settings.delimiter, self._expr[0][1]).drop_first()
+            self._question = Question([], self._settings.delimiter)
             self._refs = []
         elif self._expr_type == _TEST:
-            self._value_path = DictPath(self._delimiter, self._expr[0][1]).drop_first()
-            self._question = Question(self._expr[2:], self._delimiter)
+            self._value_path = DictPath(self._settings.delimiter, self._expr[0][1]).drop_first()
+            self._question = Question(self._expr[2:], self._settings.delimiter)
             self._refs = self._question.refs()
         elif self._expr_type == _LIST_TEST:
             self._value_path = None
-            self._question = Question(self._expr[1:], self._delimiter)
+            self._question = Question(self._expr[1:], self._settings.delimiter)
             self._refs = self._question.refs()
         else:
             raise ExpressionError('Unknown expression type: %s' % self._expr_type)
diff --git a/reclass/values/item.py b/reclass/values/item.py
index 4728142..57fd0e3 100644
--- a/reclass/values/item.py
+++ b/reclass/values/item.py
@@ -34,7 +34,7 @@
         msg = "Item class {0} does not implement contents()"
         raise NotImplementedError(msg.format(self.__class__.__name__))
 
-    def merge_over(self, item, options):
+    def merge_over(self, item):
         msg = "Item class {0} does not implement merge_over()"
         raise NotImplementedError(msg.format(self.__class__.__name__))
 
diff --git a/reclass/values/listitem.py b/reclass/values/listitem.py
index ede8251..c7f29d0 100644
--- a/reclass/values/listitem.py
+++ b/reclass/values/listitem.py
@@ -5,12 +5,14 @@
 #
 
 from item import Item
+from reclass.settings import Settings
 
 class ListItem(Item):
 
-    def __init__(self, item):
+    def __init__(self, item, settings):
         self.type = Item.LIST
         self._list = item
+        self._settings = settings
 
     def contents(self):
         return self._list
@@ -21,14 +23,14 @@
     def render(self, context, inventory):
         return self._list
 
-    def merge_over(self, item, options):
+    def merge_over(self, item):
         if item.type == Item.LIST:
             item._list.extend(self._list)
             return item
         elif item.type == Item.SCALAR:
             if item.contents() is None:
                 return self
-            elif options.allow_list_over_scalar:
+            elif self._settings.allow_list_over_scalar:
                 self._list.insert(0, item.contents())
                 return self
             else:
diff --git a/reclass/values/mergeoptions.py b/reclass/values/mergeoptions.py
deleted file mode 100644
index c5a7e59..0000000
--- a/reclass/values/mergeoptions.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from reclass.defaults import *
-
-class MergeOptions(object):
-    def __init__ (self):
-        self.allow_scalar_over_dict = MERGE_ALLOW_SCALAR_OVER_DICT
-        self.allow_scalar_over_list = MERGE_ALLOW_SCALAR_OVER_LIST
-        self.allow_list_over_scalar = MERGE_ALLOW_LIST_OVER_SCALAR
-        self.allow_dict_over_scalar = MERGE_ALLOW_DICT_OVER_SCALAR
diff --git a/reclass/values/parser.py b/reclass/values/parser.py
index c15c8d1..1b0ba4b 100644
--- a/reclass/values/parser.py
+++ b/reclass/values/parser.py
@@ -11,120 +11,31 @@
 from refitem import RefItem
 from scaitem import ScaItem
 
-from reclass.defaults import ESCAPE_CHARACTER, REFERENCE_SENTINELS, EXPORT_SENTINELS
 from reclass.errors import ParseError
-
-_STR = 1
-_REF = 2
-_INV = 3
-
-_ESCAPE = ESCAPE_CHARACTER
-_DOUBLE_ESCAPE = _ESCAPE + _ESCAPE
-
-_REF_OPEN = REFERENCE_SENTINELS[0]
-_REF_CLOSE = REFERENCE_SENTINELS[1]
-_REF_CLOSE_FIRST = _REF_CLOSE[0]
-_REF_ESCAPE_OPEN = _ESCAPE + _REF_OPEN
-_REF_ESCAPE_CLOSE = _ESCAPE + _REF_CLOSE
-_REF_DOUBLE_ESCAPE_OPEN = _DOUBLE_ESCAPE + _REF_OPEN
-_REF_DOUBLE_ESCAPE_CLOSE = _DOUBLE_ESCAPE + _REF_CLOSE
-_REF_EXCLUDES = _ESCAPE + _REF_OPEN + _REF_CLOSE
-
-_INV_OPEN = EXPORT_SENTINELS[0]
-_INV_CLOSE = EXPORT_SENTINELS[1]
-_INV_CLOSE_FIRST = _INV_CLOSE[0]
-_INV_ESCAPE_OPEN = _ESCAPE + _INV_OPEN
-_INV_ESCAPE_CLOSE = _ESCAPE + _INV_CLOSE
-_INV_DOUBLE_ESCAPE_OPEN = _DOUBLE_ESCAPE + _INV_OPEN
-_INV_DOUBLE_ESCAPE_CLOSE = _DOUBLE_ESCAPE + _INV_CLOSE
-_INV_EXCLUDES = _ESCAPE + _INV_OPEN + _INV_CLOSE
-
-_EXCLUDES = _ESCAPE + _REF_OPEN + _REF_CLOSE + _INV_OPEN + _INV_CLOSE
-
-def _string(string, location, tokens):
-    token = tokens[0]
-    tokens[0] = (_STR, token)
-
-def _reference(string, location, tokens):
-    token = list(tokens[0])
-    tokens[0] = (_REF, token)
-
-def _invquery(string, location, tokens):
-    token = list(tokens[0])
-    tokens[0] = (_INV, token)
-
-def _get_parser():
-    double_escape = pp.Combine(pp.Literal(_DOUBLE_ESCAPE) + pp.MatchFirst([pp.FollowedBy(_REF_OPEN), pp.FollowedBy(_REF_CLOSE),
-                               pp.FollowedBy(_INV_OPEN), pp.FollowedBy(_INV_CLOSE)])).setParseAction(pp.replaceWith(_ESCAPE))
-
-    ref_open = pp.Literal(_REF_OPEN).suppress()
-    ref_close = pp.Literal(_REF_CLOSE).suppress()
-    ref_not_open = ~pp.Literal(_REF_OPEN) + ~pp.Literal(_REF_ESCAPE_OPEN) + ~pp.Literal(_REF_DOUBLE_ESCAPE_OPEN)
-    ref_not_close = ~pp.Literal(_REF_CLOSE) + ~pp.Literal(_REF_ESCAPE_CLOSE) + ~pp.Literal(_REF_DOUBLE_ESCAPE_CLOSE)
-    ref_escape_open = pp.Literal(_REF_ESCAPE_OPEN).setParseAction(pp.replaceWith(_REF_OPEN))
-    ref_escape_close = pp.Literal(_REF_ESCAPE_CLOSE).setParseAction(pp.replaceWith(_REF_CLOSE))
-    ref_text = pp.CharsNotIn(_REF_EXCLUDES) | pp.CharsNotIn(_REF_CLOSE_FIRST, exact=1)
-    ref_content = pp.Combine(pp.OneOrMore(ref_not_open + ref_not_close + ref_text))
-    ref_string = pp.MatchFirst([double_escape, ref_escape_open, ref_escape_close, ref_content]).setParseAction(_string)
-    ref_item = pp.Forward()
-    ref_items = pp.OneOrMore(ref_item)
-    reference = (ref_open + pp.Group(ref_items) + ref_close).setParseAction(_reference)
-    ref_item << (reference | ref_string)
-
-    inv_open = pp.Literal(_INV_OPEN).suppress()
-    inv_close = pp.Literal(_INV_CLOSE).suppress()
-    inv_not_open = ~pp.Literal(_INV_OPEN) + ~pp.Literal(_INV_ESCAPE_OPEN) + ~pp.Literal(_INV_DOUBLE_ESCAPE_OPEN)
-    inv_not_close = ~pp.Literal(_INV_CLOSE) + ~pp.Literal(_INV_ESCAPE_CLOSE) + ~pp.Literal(_INV_DOUBLE_ESCAPE_CLOSE)
-    inv_escape_open = pp.Literal(_INV_ESCAPE_OPEN).setParseAction(pp.replaceWith(_INV_OPEN))
-    inv_escape_close = pp.Literal(_INV_ESCAPE_CLOSE).setParseAction(pp.replaceWith(_INV_CLOSE))
-    inv_text = pp.CharsNotIn(_INV_CLOSE_FIRST)
-    inv_content = pp.Combine(pp.OneOrMore(inv_not_close + inv_text))
-    inv_string = pp.MatchFirst([double_escape, inv_escape_open, inv_escape_close, inv_content]).setParseAction(_string)
-    inv_items = pp.OneOrMore(inv_string)
-    export = (inv_open + pp.Group(inv_items) + inv_close).setParseAction(_invquery)
-
-    text = pp.CharsNotIn(_EXCLUDES) | pp.CharsNotIn('', exact=1)
-    content = pp.Combine(pp.OneOrMore(ref_not_open + inv_not_open + text))
-    string = pp.MatchFirst([double_escape, ref_escape_open, inv_escape_open, content]).setParseAction(_string)
-
-    item = reference | export | string
-    line = pp.OneOrMore(item) + pp.StringEnd()
-    return line
-
-def _get_simple_ref_parser():
-    string = pp.CharsNotIn(_EXCLUDES).setParseAction(_string)
-    ref_open = pp.Literal(_REF_OPEN).suppress()
-    ref_close = pp.Literal(_REF_CLOSE).suppress()
-    reference = (ref_open + pp.Group(string) + ref_close).setParseAction(_reference)
-    line = pp.StringStart() + pp.Optional(string) + reference + pp.Optional(string) + pp.StringEnd()
-    return line
-
+from reclass.values.parser_funcs import STR, REF, INV
 
 class Parser(object):
 
-    _parser = _get_parser()
-    _simple_ref_parser = _get_simple_ref_parser()
-
-    def parse(self, value, delimiter):
-        self._delimiter = delimiter
+    def parse(self, value, settings):
+        self._settings = settings
         dollars = value.count('$')
         if dollars == 0:
             # speed up: only use pyparsing if there is a $ in the string
-            return ScaItem(value)
+            return ScaItem(value, self._settings)
         elif dollars == 1:
             # speed up: try a simple reference
             try:
-                tokens = self._simple_ref_parser.leaveWhitespace().parseString(value).asList()
+                tokens = self._settings.simple_ref_parser.leaveWhitespace().parseString(value).asList()
             except pp.ParseException as e:
                 # fall back on the full parser
                 try:
-                    tokens = self._parser.leaveWhitespace().parseString(value).asList()
+                    tokens = self._settings.ref_parser.leaveWhitespace().parseString(value).asList()
                 except pp.ParseException as e:
                     raise ParseError(e.msg, e.line, e.col, e.lineno)
         else:
             # use the full parser
             try:
-                tokens = self._parser.leaveWhitespace().parseString(value).asList()
+                tokens = self._settings.ref_parser.leaveWhitespace().parseString(value).asList()
             except pp.ParseException as e:
                 raise ParseError(e.msg, e.line, e.col, e.lineno)
 
@@ -132,22 +43,22 @@
         if len(items) == 1:
             return items[0]
         else:
-            return CompItem(items)
+            return CompItem(items, self._settings)
 
-    _create_dict = { _STR: (lambda s, v: ScaItem(v)),
-                     _REF: (lambda s, v: s._create_ref(v)),
-                     _INV: (lambda s, v: s._create_inv(v)) }
+    _create_dict = { STR: (lambda s, v: ScaItem(v, s._settings)),
+                     REF: (lambda s, v: s._create_ref(v)),
+                     INV: (lambda s, v: s._create_inv(v)) }
 
     def _create_items(self, tokens):
         return [ self._create_dict[t](self, v) for t, v in tokens ]
 
     def _create_ref(self, tokens):
         items = [ self._create_dict[t](self, v) for t, v in tokens ]
-        return RefItem(items, self._delimiter)
+        return RefItem(items, self._settings)
 
     def _create_inv(self, tokens):
-        items = [ ScaItem(v) for t, v in tokens ]
+        items = [ ScaItem(v, self._settings) for t, v in tokens ]
         if len(items) == 1:
-            return InvItem(items[0], self._delimiter)
+            return InvItem(items[0], self._settings)
         else:
-            return InvItem(CompItem(items), self._delimiter)
+            return InvItem(CompItem(items), self._settings)
diff --git a/reclass/values/parser_funcs.py b/reclass/values/parser_funcs.py
new file mode 100644
index 0000000..bd5a1ba
--- /dev/null
+++ b/reclass/values/parser_funcs.py
@@ -0,0 +1,99 @@
+#
+# -*- coding: utf-8 -*-
+#
+# This file is part of reclass
+#
+
+import pyparsing as pp
+
+STR = 1
+REF = 2
+INV = 3
+
+def _string(string, location, tokens):
+    token = tokens[0]
+    tokens[0] = (STR, token)
+
+def _reference(string, location, tokens):
+    token = list(tokens[0])
+    tokens[0] = (REF, token)
+
+def _invquery(string, location, tokens):
+    token = list(tokens[0])
+    tokens[0] = (INV, token)
+
+def get_ref_parser(escape_character, reference_sentinels, export_sentinels):
+    _ESCAPE = escape_character
+    _DOUBLE_ESCAPE = _ESCAPE + _ESCAPE
+
+    _REF_OPEN = reference_sentinels[0]
+    _REF_CLOSE = reference_sentinels[1]
+    _REF_CLOSE_FIRST = _REF_CLOSE[0]
+    _REF_ESCAPE_OPEN = _ESCAPE + _REF_OPEN
+    _REF_ESCAPE_CLOSE = _ESCAPE + _REF_CLOSE
+    _REF_DOUBLE_ESCAPE_OPEN = _DOUBLE_ESCAPE + _REF_OPEN
+    _REF_DOUBLE_ESCAPE_CLOSE = _DOUBLE_ESCAPE + _REF_CLOSE
+    _REF_EXCLUDES = _ESCAPE + _REF_OPEN + _REF_CLOSE
+
+    _INV_OPEN = export_sentinels[0]
+    _INV_CLOSE = export_sentinels[1]
+    _INV_CLOSE_FIRST = _INV_CLOSE[0]
+    _INV_ESCAPE_OPEN = _ESCAPE + _INV_OPEN
+    _INV_ESCAPE_CLOSE = _ESCAPE + _INV_CLOSE
+    _INV_DOUBLE_ESCAPE_OPEN = _DOUBLE_ESCAPE + _INV_OPEN
+    _INV_DOUBLE_ESCAPE_CLOSE = _DOUBLE_ESCAPE + _INV_CLOSE
+    _INV_EXCLUDES = _ESCAPE + _INV_OPEN + _INV_CLOSE
+
+    _EXCLUDES = _ESCAPE + _REF_OPEN + _REF_CLOSE + _INV_OPEN + _INV_CLOSE
+
+    double_escape = pp.Combine(pp.Literal(_DOUBLE_ESCAPE) + pp.MatchFirst([pp.FollowedBy(_REF_OPEN), pp.FollowedBy(_REF_CLOSE),
+                               pp.FollowedBy(_INV_OPEN), pp.FollowedBy(_INV_CLOSE)])).setParseAction(pp.replaceWith(_ESCAPE))
+
+    ref_open = pp.Literal(_REF_OPEN).suppress()
+    ref_close = pp.Literal(_REF_CLOSE).suppress()
+    ref_not_open = ~pp.Literal(_REF_OPEN) + ~pp.Literal(_REF_ESCAPE_OPEN) + ~pp.Literal(_REF_DOUBLE_ESCAPE_OPEN)
+    ref_not_close = ~pp.Literal(_REF_CLOSE) + ~pp.Literal(_REF_ESCAPE_CLOSE) + ~pp.Literal(_REF_DOUBLE_ESCAPE_CLOSE)
+    ref_escape_open = pp.Literal(_REF_ESCAPE_OPEN).setParseAction(pp.replaceWith(_REF_OPEN))
+    ref_escape_close = pp.Literal(_REF_ESCAPE_CLOSE).setParseAction(pp.replaceWith(_REF_CLOSE))
+    ref_text = pp.CharsNotIn(_REF_EXCLUDES) | pp.CharsNotIn(_REF_CLOSE_FIRST, exact=1)
+    ref_content = pp.Combine(pp.OneOrMore(ref_not_open + ref_not_close + ref_text))
+    ref_string = pp.MatchFirst([double_escape, ref_escape_open, ref_escape_close, ref_content]).setParseAction(_string)
+    ref_item = pp.Forward()
+    ref_items = pp.OneOrMore(ref_item)
+    reference = (ref_open + pp.Group(ref_items) + ref_close).setParseAction(_reference)
+    ref_item << (reference | ref_string)
+
+    inv_open = pp.Literal(_INV_OPEN).suppress()
+    inv_close = pp.Literal(_INV_CLOSE).suppress()
+    inv_not_open = ~pp.Literal(_INV_OPEN) + ~pp.Literal(_INV_ESCAPE_OPEN) + ~pp.Literal(_INV_DOUBLE_ESCAPE_OPEN)
+    inv_not_close = ~pp.Literal(_INV_CLOSE) + ~pp.Literal(_INV_ESCAPE_CLOSE) + ~pp.Literal(_INV_DOUBLE_ESCAPE_CLOSE)
+    inv_escape_open = pp.Literal(_INV_ESCAPE_OPEN).setParseAction(pp.replaceWith(_INV_OPEN))
+    inv_escape_close = pp.Literal(_INV_ESCAPE_CLOSE).setParseAction(pp.replaceWith(_INV_CLOSE))
+    inv_text = pp.CharsNotIn(_INV_CLOSE_FIRST)
+    inv_content = pp.Combine(pp.OneOrMore(inv_not_close + inv_text))
+    inv_string = pp.MatchFirst([double_escape, inv_escape_open, inv_escape_close, inv_content]).setParseAction(_string)
+    inv_items = pp.OneOrMore(inv_string)
+    export = (inv_open + pp.Group(inv_items) + inv_close).setParseAction(_invquery)
+
+    text = pp.CharsNotIn(_EXCLUDES) | pp.CharsNotIn('', exact=1)
+    content = pp.Combine(pp.OneOrMore(ref_not_open + inv_not_open + text))
+    string = pp.MatchFirst([double_escape, ref_escape_open, inv_escape_open, content]).setParseAction(_string)
+
+    item = reference | export | string
+    line = pp.OneOrMore(item) + pp.StringEnd()
+    return line
+
+def get_simple_ref_parser(escape_character, reference_sentinels, export_sentinels):
+    _ESCAPE = escape_character
+    _REF_OPEN = reference_sentinels[0]
+    _REF_CLOSE = reference_sentinels[1]
+    _INV_OPEN = export_sentinels[0]
+    _INV_CLOSE = export_sentinels[1]
+    _EXCLUDES = _ESCAPE + _REF_OPEN + _REF_CLOSE + _INV_OPEN + _INV_CLOSE
+
+    string = pp.CharsNotIn(_EXCLUDES).setParseAction(_string)
+    ref_open = pp.Literal(_REF_OPEN).suppress()
+    ref_close = pp.Literal(_REF_CLOSE).suppress()
+    reference = (ref_open + pp.Group(string) + ref_close).setParseAction(_reference)
+    line = pp.StringStart() + pp.Optional(string) + reference + pp.Optional(string) + pp.StringEnd()
+    return line
diff --git a/reclass/values/refitem.py b/reclass/values/refitem.py
index a69bbf5..ebb9708 100644
--- a/reclass/values/refitem.py
+++ b/reclass/values/refitem.py
@@ -5,14 +5,15 @@
 #
 
 from item import Item
+from reclass.settings import Settings
 from reclass.utils.dictpath import DictPath
 from reclass.errors import ResolveError
 
 class RefItem(Item):
 
-    def __init__(self, items, delimiter):
+    def __init__(self, items, settings):
         self.type = Item.REFERENCE
-        self._delimiter = delimiter
+        self._settings = settings
         self._items = items
         self._refs = []
         self._allRefs = False
@@ -47,7 +48,7 @@
         return self._refs
 
     def _resolve(self, ref, context):
-        path = DictPath(self._delimiter, ref)
+        path = DictPath(self._settings.delimiter, ref)
         try:
             return path.get_value(context)
         except (KeyError, TypeError) as e:
diff --git a/reclass/values/scaitem.py b/reclass/values/scaitem.py
index 151e123..df574d9 100644
--- a/reclass/values/scaitem.py
+++ b/reclass/values/scaitem.py
@@ -4,27 +4,29 @@
 # This file is part of reclass
 #
 
+from reclass.settings import Settings
 from item import Item
 
 class ScaItem(Item):
 
-    def __init__(self, value):
+    def __init__(self, value, settings):
         self.type = Item.SCALAR
         self._value = value
+        self._settings = settings
 
     def contents(self):
         return self._value
 
-    def merge_over(self, item, options):
+    def merge_over(self, item):
         if item.type == Item.SCALAR:
             return self
         elif item.type == Item.LIST:
-            if options.allow_scalar_over_list:
+            if self._settings.allow_scalar_over_list:
                 return self
             else:
                 raise TypeError('allow scalar over list = False: cannot merge %s over %s' % (repr(self), repr(item)))
         elif item.type == Item.DICTIONARY:
-            if options.allow_scalar_over_dict:
+            if self._settings.allow_scalar_over_dict:
                 return self
             else:
                 raise TypeError('allow scalar over dict = False: cannot merge %s over %s' % (repr(self), repr(item)))
diff --git a/reclass/values/tests/test_value.py b/reclass/values/tests/test_value.py
index 1b83094..51425cc 100644
--- a/reclass/values/tests/test_value.py
+++ b/reclass/values/tests/test_value.py
@@ -9,16 +9,17 @@
 
 import pyparsing as pp
 
+from reclass.settings import Settings
 from reclass.values.value import Value
-from reclass.defaults import REFERENCE_SENTINELS, \
-        PARAMETER_INTERPOLATION_DELIMITER
 from reclass.errors import ResolveError, \
         IncompleteInterpolationError, ParseError
 import unittest
 
+SETTINGS = Settings()
+
 def _var(s):
-    return '%s%s%s' % (REFERENCE_SENTINELS[0], s,
-                       REFERENCE_SENTINELS[1])
+    return '%s%s%s' % (SETTINGS.reference_sentinels[0], s,
+                       SETTINGS.reference_sentinels[1])
 
 CONTEXT = {'favcolour':'yellow',
            'motd':{'greeting':'Servus!',
@@ -37,13 +38,13 @@
 
     def test_simple_string(self):
         s = 'my cat likes to hide in boxes'
-        tv = Value(s)
+        tv = Value(s, SETTINGS, '')
         self.assertFalse(tv.has_references())
         self.assertEquals(tv.render(CONTEXT, None), s)
 
     def _test_solo_ref(self, key):
         s = _var(key)
-        tv = Value(s)
+        tv = Value(s, SETTINGS, '')
         res = tv.render(CONTEXT, None)
         self.assertTrue(tv.has_references())
         self.assertEqual(res, CONTEXT[key])
@@ -65,7 +66,7 @@
 
     def test_single_subst_bothends(self):
         s = 'I like ' + _var('favcolour') + ' and I like it'
-        tv = Value(s)
+        tv = Value(s, SETTINGS, '')
         self.assertTrue(tv.has_references())
         self.assertEqual(tv.render(CONTEXT, None),
                          _poor_mans_template(s, 'favcolour',
@@ -73,7 +74,7 @@
 
     def test_single_subst_start(self):
         s = _var('favcolour') + ' is my favourite colour'
-        tv = Value(s)
+        tv = Value(s, SETTINGS, '')
         self.assertTrue(tv.has_references())
         self.assertEqual(tv.render(CONTEXT, None),
                          _poor_mans_template(s, 'favcolour',
@@ -81,34 +82,34 @@
 
     def test_single_subst_end(self):
         s = 'I like ' + _var('favcolour')
-        tv = Value(s)
+        tv = Value(s, SETTINGS, '')
         self.assertTrue(tv.has_references())
         self.assertEqual(tv.render(CONTEXT, None),
                          _poor_mans_template(s, 'favcolour',
                                              CONTEXT['favcolour']))
 
     def test_deep_subst_solo(self):
-        var = PARAMETER_INTERPOLATION_DELIMITER.join(('motd', 'greeting'))
-        s = _var(var)
-        tv = Value(s)
+        motd = SETTINGS.delimiter.join(('motd', 'greeting'))
+        s = _var(motd)
+        tv = Value(s, SETTINGS, '')
         self.assertTrue(tv.has_references())
         self.assertEqual(tv.render(CONTEXT, None),
-                         _poor_mans_template(s, var,
+                         _poor_mans_template(s, motd,
                                              CONTEXT['motd']['greeting']))
 
     def test_multiple_subst(self):
-        greet = PARAMETER_INTERPOLATION_DELIMITER.join(('motd', 'greeting'))
+        greet = SETTINGS.delimiter.join(('motd', 'greeting'))
         s = _var(greet) + ' I like ' + _var('favcolour') + '!'
-        tv = Value(s)
+        tv = Value(s, SETTINGS, '')
         self.assertTrue(tv.has_references())
         want = _poor_mans_template(s, greet, CONTEXT['motd']['greeting'])
         want = _poor_mans_template(want, 'favcolour', CONTEXT['favcolour'])
         self.assertEqual(tv.render(CONTEXT, None), want)
 
     def test_multiple_subst_flush(self):
-        greet = PARAMETER_INTERPOLATION_DELIMITER.join(('motd', 'greeting'))
+        greet = SETTINGS.delimiter.join(('motd', 'greeting'))
         s = _var(greet) + ' I like ' + _var('favcolour')
-        tv = Value(s)
+        tv = Value(s, SETTINGS, '')
         self.assertTrue(tv.has_references())
         want = _poor_mans_template(s, greet, CONTEXT['motd']['greeting'])
         want = _poor_mans_template(want, 'favcolour', CONTEXT['favcolour'])
@@ -116,14 +117,14 @@
 
     def test_undefined_variable(self):
         s = _var('no_such_variable')
-        tv = Value(s)
+        tv = Value(s, SETTINGS, '')
         with self.assertRaises(ResolveError):
             tv.render(CONTEXT, None)
 
     def test_incomplete_variable(self):
-        s = REFERENCE_SENTINELS[0] + 'incomplete'
+        s = SETTINGS.reference_sentinels[0] + 'incomplete'
         with self.assertRaises(ParseError):
-            tv = Value(s)
+            tv = Value(s, SETTINGS, '')
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/reclass/values/value.py b/reclass/values/value.py
index fcca3ba..23401fb 100644
--- a/reclass/values/value.py
+++ b/reclass/values/value.py
@@ -8,24 +8,23 @@
 from dictitem import DictItem
 from listitem import ListItem
 from scaitem import ScaItem
-from reclass.defaults import PARAMETER_INTERPOLATION_DELIMITER
 from reclass.errors import ResolveError
 
 class Value(object):
 
     _parser = Parser()
 
-    def __init__(self, value, uri=None, delimiter=PARAMETER_INTERPOLATION_DELIMITER):
-        self._delimiter = delimiter
+    def __init__(self, value, settings, uri):
+        self._settings = settings
         self._uri = uri
         if isinstance(value, str):
-            self._item = self._parser.parse(value, delimiter)
+            self._item = self._parser.parse(value, self._settings)
         elif isinstance(value, list):
-            self._item = ListItem(value)
+            self._item = ListItem(value, self._settings)
         elif isinstance(value, dict):
-            self._item = DictItem(value)
+            self._item = DictItem(value, self._settings)
         else:
-            self._item = ScaItem(value)
+            self._item = ScaItem(value, self._settings)
 
     def is_container(self):
         return self._item.is_container()
@@ -49,7 +48,7 @@
         if self._item.has_references():
             self._item.assembleRefs(context)
 
-    def render(self, context, inventory, options=None):
+    def render(self, context, inventory):
         try:
             return self._item.render(context, inventory)
         except ResolveError as e:
@@ -59,8 +58,8 @@
     def contents(self):
         return self._item.contents()
 
-    def merge_over(self, value, options):
-        self._item = self._item.merge_over(value._item, options)
+    def merge_over(self, value):
+        self._item = self._item.merge_over(value._item)
         return self
 
     def __repr__(self):
diff --git a/reclass/values/valuelist.py b/reclass/values/valuelist.py
index 3dc9c62..64a7cb5 100644
--- a/reclass/values/valuelist.py
+++ b/reclass/values/valuelist.py
@@ -8,7 +8,8 @@
 
 class ValueList(object):
 
-    def __init__(self, value):
+    def __init__(self, value, settings):
+        self._settings = settings
         self._refs = []
         self._allRefs = True
         self._values = [ value ]
@@ -59,16 +60,16 @@
             if value.allRefs() is False:
                 self._allRefs = False
 
-    def merge(self, options):
+    def merge(self):
         output = None
         for n, value in enumerate(self._values):
             if output is None:
                 output = value
             else:
-                output = value.merge_over(output, options)
+                output = value.merge_over(output)
         return output
 
-    def render(self, context, inventory, options):
+    def render(self, context, inventory):
         from reclass.datatypes.parameters import Parameters
 
         output = None
@@ -80,8 +81,8 @@
             else:
                 new = value.render(context, inventory)
                 if isinstance(output, dict) and isinstance(new, dict):
-                    p1 = Parameters(output, delimiter=value._delimiter)
-                    p2 = Parameters(new, delimiter=value._delimiter)
+                    p1 = Parameters(output, self._settings, None)
+                    p2 = Parameters(new, self._settings, None)
                     p1.merge(p2)
                     output = p1.as_dict()
                     continue