Passed
Push — master ( 454cf7...0d52c3 )
by Kacper
02:57
created

Token   B

Complexity

Total Complexity 45

Size/Duplication

Total Lines 226
Duplicated Lines 8.85 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 96.81%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 45
c 2
b 0
f 0
lcom 1
cbo 3
dl 20
loc 226
rs 8.3673
ccs 91
cts 94
cp 0.9681

16 Methods

Rating   Name   Duplication   Size   Complexity  
D __construct() 0 36 8
B compare() 0 20 11
A isStart() 0 4 1
A isEnd() 0 4 1
A isValid() 0 8 2
A validate() 0 7 3
A setValid() 0 10 3
A getStart() 0 4 1
A setStart() 10 10 2
A getEnd() 0 4 1
A setEnd() 10 10 2
A getRule() 0 4 1
A setRule() 0 4 1
A getLength() 0 8 3
A dump() 0 16 4
A __get() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Token often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Token, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Highlighter
4
 *
5
 * Copyright (C) 2015, Some right reserved.
6
 *
7
 * @author Kacper "Kadet" Donat <[email protected]>
8
 *
9
 * Contact with author:
10
 * Xmpp: [email protected]
11
 * E-mail: [email protected]
12
 *
13
 * From Kadet with love.
14
 */
15
16
namespace Kadet\Highlighter\Parser\Token;
17
18
use Kadet\Highlighter\Language\Language;
19
use Kadet\Highlighter\Parser\Rule;
20
use Kadet\Highlighter\Parser\Validator\Validator;
21
use Kadet\Highlighter\Utils\Helper;
22
use Kadet\Highlighter\Utils\StringHelper;
23
24
class Token
25
{
26
    const NAME  = null;
27
    const START = 0x1;
28
    const END   = 0x2;
29
30
    protected static $_id = 0;
31
32
    public $pos;
33
    public $name;
34
    public $closedBy;
35
    public $index = 1;
36
37
    /**
38
     * @var Token|null|false
39
     */
40
    protected $_end;
41
42
    /**
43
     * @var Token|null|false
44
     */
45
    protected $_start;
46
47
    /** @var Rule */
48
    protected $_rule;
49
50
    protected $_valid;
51
    protected $_length;
52
53
    public $id;
54
55
    /**
56
     * Token constructor.
57
     *
58
     * @param array $options
59
     */
60 52
    public function __construct(array $options)
61
    {
62 52
        if (isset($options[0])) {
63 39
            $this->name = $options[0];
64 39
        }
65
66 52
        if (isset($options['pos'])) {
67 49
            $this->pos = $options['pos'];
68 49
        }
69
70 52
        if (isset($options['index'])) {
71 6
            $this->index = $options['index'];
72 6
        }
73
74 52
        if (isset($options['start'])) {
75 2
            $this->setStart($options['start']);
76 2
        }
77
78 52
        if (isset($options['rule'])) {
79 19
            $this->setRule($options['rule']);
80 19
        } else {
81 34
            $this->setRule(new Rule());
82
        }
83
84 52
        if (isset($options['end'])) {
85 42
            $this->setEnd($options['end']);
86 42
        }
87
88 52
        if (isset($options['closed-by'])) {
89
            $this->closedBy = $options['closed-by'];
90
        } else {
91 52
            $this->closedBy = $this->name;
92
        }
93
94 52
        $this->id = ++self::$_id;
95 52
    }
96
97 13
    public static function compare(Token $a, Token $b)
98
    {
99 13
        $multiplier = $a->isEnd() ? -1 : 1;
100
101 13
        if (($a->isStart() && $b->isEnd()) || ($a->isEnd() && $b->isStart())) {
102 1
            if ($a->getStart() == $b) {
103 1
                return 1;
104 1
            } elseif ($a->getEnd() == $b) {
105
                return -1;
106
            } else {
107 1
                return $multiplier;
108
            }
109 12
        } elseif (($rule = Helper::cmp($b->_rule->priority, $a->_rule->priority)) !== 0) {
110 10
            return $multiplier*$rule;
111 5
        } elseif (($rule = Helper::cmp($b->index, $a->index)) !== 0) {
112 1
            return $multiplier*$rule;
113
        } else {
114 4
            return $multiplier*($a->id < $b->id ? -1 : 1);
115
        }
116
    }
117
118 35
    public function isStart()
119
    {
120 35
        return $this->_start === null;
121
    }
122
123 33
    public function isEnd()
124
    {
125 33
        return $this->_end === null;
126
    }
127
128 16
    public function isValid(Language $language, $context = null)
129
    {
130 16
        if ($this->_valid === null) {
131 15
            $this->validate($language, $context);
132 15
        }
133
134 16
        return $this->_valid;
135
    }
136
137 11
    protected function validate(Language $language, $context)
138
    {
139 11
        $this->setValid(
140 11
            $language === $this->_rule->language &&
141 11
            $this->_rule->validate($context, $this->isEnd() ? [$this->name => Validator::CONTEXT_IN] : [])
142 11
        );
143 11
    }
144
145 15
    public function setValid($valid = true)
146
    {
147 15
        $this->_valid = $valid;
148
149 15
        if ($this->_end) {
150 12
            $this->_end->_valid = $this->_valid;
151 15
        } elseif ($this->_start) {
152 12
            $this->_start->_valid = $this->_valid;
153 12
        }
154 15
    }
155
156
    /**
157
     * @return mixed
158
     */
159 29
    public function getStart()
160
    {
161 29
        return $this->_start;
162
    }
163
164
    /**
165
     * @param Token|null|false $start
166
     */
167 3 View Code Duplication
    public function setStart($start = null)
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
168
    {
169 3
        $this->_end   = null;
170 3
        $this->_start = $start;
171
172 3
        if ($start instanceof Token) {
173 2
            $this->_start->_length = null;
174 2
            $start->_end = $this;
175 2
        }
176 3
    }
177
178
    /**
179
     * @return Token|null
180
     */
181 40
    public function getEnd()
182
    {
183 40
        return $this->_end;
184
    }
185
186
    /**
187
     * @param Token|null|false $end
188
     */
189 42 View Code Duplication
    public function setEnd($end = null)
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
190
    {
191 42
        $this->_start  = null;
192 42
        $this->_end    = $end;
193 42
        $this->_length = null;
194
195 42
        if ($end instanceof Token) {
196 42
            $end->_start = $this;
197 42
        }
198 42
    }
199
200
    /**
201
     * @return Rule
202
     */
203 16
    public function getRule()
204
    {
205 16
        return $this->_rule;
206
    }
207
208
    /**
209
     * @param Rule $rule
210
     */
211 52
    public function setRule(Rule $rule)
212
    {
213 52
        $this->_rule = $rule;
214 52
    }
215
216 2
    public function getLength()
217
    {
218 2
        if ($this->_length === null) {
219 2
            $this->_length = $this->_end === null ? 0 : $this->_end->pos - $this->pos;
220 2
        }
221
222 2
        return $this->_length;
223
    }
224
225
    /**
226
     * @codeCoverageIgnore
227
     */
228
    public function dump($text = null)
229
    {
230
        $pos = StringHelper::positionToLine($text, $this->pos);
231
        $pos = $pos['line'] . ':' . $pos['pos'];
232
233
        if ($this->isStart()) {
234
            $result = "Start ({$this->name}) $pos";
235
            if ($text !== null && $this->_end !== null) {
236
                $result .= "  \x02" . substr($text, $this->pos, $this->_end->pos - $this->pos) . "\x03";
237
            }
238
        } else {
239
            $result = "End ({$this->name}) $pos";
240
        }
241
242
        return $result;
243
    }
244
245 11
    public function __get($name)
246
    {
247 11
        return $this->getRule()->$name;
248
    }
249
}
250