Passed
Push — master ( cb153d...4ecc61 )
by Max
43s
created

structured_data._destructure   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 83
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 57
dl 0
loc 83
rs 10
c 0
b 0
f 0
wmc 18

9 Methods

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