blob: 0834a3eb7bc48add8d0a507cecb60afe3b14d1ff [file] [log] [blame]
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""This module defines an interface of a meta structure -- ``MetaObject``.
We can consider ``MetaObject`` as inner node, and it has ``is_meta`` property.
``MetaObject`` is good way to group leaf nodes (which have some real value).
An easy example for ``MetaDict``:
MetaDict({'a': 1, 'b': MetaDict({'c': 2, 'd': 3})}), its leaves are
{'a': 1, 'c': 2, 'd': 3}.
An use case in Predator is that being a subclass of ``MetaDict``,
``MetaFeature`` can group relevant features together to share common
operations.
"""
class MetaObject(object):
"""Class that can be either one element or a collection of elements."""
@property
def is_meta(self): # pragma: no cover
return True
class MetaDict(dict, MetaObject):
"""Dict-like object containing a collection of ``MetaObject``s."""
@property
def leaves(self):
"""Gets a dict of all leaf items."""
leaves = {}
for key, value in self.iteritems():
if not hasattr(value, 'is_meta'):
leaves[key] = value
else:
leaves.update(value.leaves)
return leaves
def iterleaves(self):
"""Iterates leaf items."""
for key, value in self.iteritems():
if not hasattr(value, 'is_meta'):
yield (key, value)
else:
for sub_key, sub_value in value.iterleaves():
yield (sub_key, sub_value)
def UpdateLeaves(self, leaves):
"""Update leaf nodes by a dict - ``leaves``."""
for key, value in self.iteritems():
if not hasattr(value, 'is_meta'):
if key in leaves:
self[key] = leaves[key]
else:
value.UpdateLeaves(leaves)
def __eq__(self, other):
for key, value in self.iteritems():
if key not in other or value != other[key]:
return False
return True
def __ne__(self, other):
return not self.__eq__(other)