Completed
Branch 0.8-dev (5d9532)
by Kacper
02:49
created

Token   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 214
Duplicated Lines 9.35 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 98.96%

Importance

Changes 10
Bugs 0 Features 0
Metric Value
wmc 43
c 10
b 0
f 0
lcom 1
cbo 4
dl 20
loc 214
ccs 95
cts 96
cp 0.9896
rs 8.3157

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 16 4
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 getLength() 0 8 3
A __get() 0 4 1
A process() 0 9 3
A processStart() 0 6 1
A processEnd() 0 17 4
B compare() 0 20 11

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) 2016, 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\Context;
20
use Kadet\Highlighter\Parser\Result;
21
use Kadet\Highlighter\Parser\Rule;
22
use Kadet\Highlighter\Parser\TokenIterator;
23
use Kadet\Highlighter\Parser\Validator\Validator;
24
use Kadet\Highlighter\Utils\Helper;
25
26
class Token
27
{
28
    const NAME  = null;
29
    const START = 0x1;
30
    const END   = 0x2;
31
32
    protected static $_id = 0;
33
34
    public $pos;
35
    public $name;
36
    public $index = 1;
37
    public $id;
38
    public $rule;
39
40
    # region >>> cache
41
    /**
42
     * @var static|null|false
43
     */
44
    protected $_end;
45
46
    /**
47
     * @var static|null|false
48
     */
49
    protected $_start;
50
51
    protected $_valid;
52
    protected $_length;
53
    # endregion
54
55
    /**
56
     * Token constructor.
57
     *
58
     * @param null  $name
59
     * @param array $options
60
     */
61 48
    public function __construct($name = null, array $options = [])
62
    {
63 48
        $this->name     = $name;
64
65 48
        if (isset($options['pos'])) {
66 45
            $this->pos = $options['pos'];
67 45
        }
68
69 48
        if (isset($options['index'])) {
70 33
            $this->index = $options['index'];
71 6
        }
72
73 48
        $this->rule = isset($options['rule']) ? $options['rule'] : new Rule();
74
75 48
        $this->id = ++self::$_id;
76 48
    }
77
78 33
    public function isStart()
79
    {
80 33
        return $this->_start === null;
81
    }
82
83 31
    public function isEnd()
84
    {
85 31
        return $this->_end === null;
86
    }
87
88 14
     public function isValid(Context $context)
89
    {
90 14
        if ($this->_valid === null) {
91 13
            $this->validate($context);
92 13
        }
93
94 14
        return $this->_valid;
95
    }
96
97 11
    protected function validate(Context $context)
98
    {
99 11
        $this->setValid(
100 11
            $context->language === $this->rule->language &&
101 11
            $this->rule->validator->validate($context, $this->isEnd() ? [$this->name => Validator::CONTEXT_IN] : [])
102 11
        );
103 11
    }
104
105 14
    public function setValid($valid = true)
106
    {
107 14
        $this->_valid = $valid;
108
109 14
        if ($this->_end) {
110 11
            $this->_end->_valid = $this->_valid;
111 14
        } elseif ($this->_start) {
112 12
            $this->_start->_valid = $this->_valid;
113 12
        }
114 14
    }
115
116
    /**
117
     * @return Token|null|false
118
     */
119 29
    public function getStart()
120
    {
121 29
        return $this->_start;
122
    }
123
124
    /**
125
     * @param Token|null|false $start
126
     */
127 11 View Code Duplication
    public function setStart($start = null)
128
    {
129 11
        $this->_end   = null;
130 11
        $this->_start = $start;
131
132 11
        if ($start instanceof Token) {
133 11
            $this->_start->_length = null;
134 11
            $start->_end = $this;
135 11
        }
136 11
    }
137
138
    /**
139
     * @return Token|null|false
140
     */
141 38
    public function getEnd()
142
    {
143 38
        return $this->_end;
144
    }
145
146
    /**
147
     * @param Token|null|false $end
148
     */
149 46 View Code Duplication
    public function setEnd($end = null)
150
    {
151 46
        $this->_start  = null;
152 46
        $this->_end    = $end;
153 46
        $this->_length = null;
154
155 46
        if ($end instanceof Token) {
156 46
            $end->_start = $this;
157 46
        }
158 46
    }
159
160 2
    public function getLength()
161
    {
162 2
        if ($this->_length === null) {
163 2
            $this->_length = !$this->_end ? 0 : $this->_end->pos - $this->pos;
164 2
        }
165
166 2
        return $this->_length;
167
    }
168
169 11
    public function __get($name)
170
    {
171 11
        return $this->rule->$name;
172
    }
173
174
    /**
175
     * @param Context       $context
176
     * @param Language      $language
177
     * @param Result        $result
178
     * @param TokenIterator $tokens
179
     *
180
     * todo: Documentation
181
     *
182
     * @return bool Return true to continue processing, false to return already processed tokens.
183
     */
184 11
    public function process(Context $context, Language $language, Result $result, TokenIterator $tokens) {
185 11
        if(!$this->isValid($context)) {
186 3
            return true;
187
        }
188
189 11
        return $this->isStart() ?
190 11
            $this->processStart($context, $language, $result, $tokens) :
191 11
            $this->processEnd($context, $language, $result, $tokens);
192
    }
193
194 10
    protected function processStart(Context $context, Language $language, Result $result, TokenIterator $tokens) {
1 ignored issue
show
Unused Code introduced by
The parameter $language is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
195 10
        $result->append($this);
196 10
        $context->push($this);
197
198 10
        return true;
199
    }
200
201 9
    protected function processEnd(Context $context, Language $language, Result $result, TokenIterator $tokens) {
1 ignored issue
show
Unused Code introduced by
The parameter $language is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
202 9
        if($this->_start) {
203 8
            $context->pop($this->_start);
204 8
        } else {
205 1
            if (($start = $context->find($this->name)) !== false) {
206 1
                $this->setStart($tokens[$start]);
207
208 1
                unset($context->stack[$start]);
209 1
            }
210
        }
211
212 9
        if (!$this->_start instanceof MetaToken) {
213 9
            $result->append($this);
214 9
        }
215
216 9
        return true;
217
    }
218
219 13
    public static function compare(Token $a, Token $b)
220
    {
221 13
        $multiplier = $a->isEnd() ? -1 : 1;
222
223 13
        if (($a->isStart() && $b->isEnd()) || ($a->isEnd() && $b->isStart())) {
224 1
            if ($a->getStart() == $b) {
225 1
                return 1;
226 1
            } elseif ($a->getEnd() == $b) {
227
                return -1;
228
            } else {
229 1
                return $multiplier;
230
            }
231 12
        } elseif (($rule = Helper::cmp($b->rule->priority, $a->rule->priority)) !== 0) {
232 10
            return $multiplier*$rule;
233 4
        } elseif (($rule = Helper::cmp($b->index, $a->index)) !== 0) {
234 1
            return $multiplier*$rule;
235
        } else {
236 3
            return $multiplier*($a->id < $b->id ? -1 : 1);
237
        }
238
    }
239
}
240