Passed
Push — master ( 062c67...ecf06d )
by Max
47s
created

structured_data._destructure   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 88
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 60
dl 0
loc 88
rs 10
c 0
b 0
f 0
wmc 19

10 Methods

Rating   Name   Duplication   Size   Complexity  
A Destructurer.__call__() 0 2 1
A Destructurer.__init__() 0 2 1
A ADTDestructurer.destructure() 0 4 2
A TupleDestructurer.destructure() 0 4 3
A Destructurer.destructure() 0 2 1
A AsPatternDestructurer.destructure() 0 4 2
A DestructurerList.names() 0 15 4
A DestructurerList.get_destructurer() 0 5 3
A DestructurerList.custom() 0 3 1
A DestructurerList.__new__() 0 2 1
1
from ._adt_constructor import ADTConstructor
2
from ._match_failure import MatchFailure
3
from ._not_in import not_in
4
from ._patterns import AsPattern
5
from ._patterns import Pattern
6
from ._unpack import unpack
7
8
9
class Destructurer:
10
11
    def __init__(self, target):
12
        self.target = target
13
14
    def __call__(self, value):
15
        return self.destructure(value)
16
17
    def destructure(self, value):
18
        raise NotImplementedError
19
20
    type = None
21
22
23
class AsPatternDestructurer(Destructurer):
24
25
    def destructure(self, value):
26
        if self.target is value:
27
            return reversed(self.target)
28
        return (value, value)
29
30
    type = AsPattern
31
32
33
class ADTDestructurer(Destructurer):
34
35
    def destructure(self, value):
36
        if value.__class__ is not self.target.__class__:
37
            raise MatchFailure
38
        return reversed(unpack(value))
39
40
    type = ADTConstructor
41
42
43
class TupleDestructurer(Destructurer):
44
45
    def destructure(self, value):
46
        if isinstance(value, self.target.__class__) and len(self.target) == len(value):
47
            return reversed(value)
48
        raise MatchFailure
49
50
    type = tuple
51
52
53
class DestructurerList(tuple):
54
55
    __slots__ = ()
56
57
    def __new__(cls, *destructurers):
58
        return super().__new__(cls, destructurers)
59
60
    def get_destructurer(self, item):
61
        for destructurer in self:
62
            if isinstance(item, destructurer.type):
63
                return destructurer(item)
64
        return None
65
66
    @classmethod
67
    def custom(cls, *destructurers):
68
        return cls(AsPatternDestructurer, ADTDestructurer, *destructurers, TupleDestructurer)
69
70
    def names(self, target):
71
        name_list = []
72
        names_seen = set()
73
        to_process = [target]
74
        while to_process:
75
            item = to_process.pop()
76
            if isinstance(item, Pattern):
77
                not_in(names_seen, item.name)
78
                names_seen.add(item.name)
79
                name_list.append(item.name)
80
            else:
81
                destructurer = self.get_destructurer(item)
82
                if destructurer:
83
                    to_process.extend(destructurer(item))
84
        return name_list
85
86
87
DESTRUCTURERS = DestructurerList.custom()
88