Passed
Branch 0.8-dev (82421f)
by Kacper
02:45
created

Token   B

Complexity

Total Complexity 41

Size/Duplication

Total Lines 208
Duplicated Lines 9.62 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 98.95%

Importance

Changes 12
Bugs 0 Features 0
Metric Value
c 12
b 0
f 0
dl 20
loc 208
wmc 41
lcom 1
cbo 4
rs 8.2769
ccs 94
cts 95
cp 0.9895

16 Methods

Rating   Name   Duplication   Size   Complexity  
A processStart() 0 6 1
B compare() 0 18 10
A __construct() 0 12 3
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 processEnd() 0 17 4

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 $id;
37
    public $rule;
38
    public $options;
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 52
    public function __construct($name = null, array $options = [])
62
    {
63 52
        if (isset($options['pos'])) {
64 45
            $this->pos = $options['pos'];
65 45
        }
66
67 52
        $this->name     = $name;
68 52
        $this->rule     = isset($options['rule']) ? $options['rule'] : new Rule();
69 52
        $this->options &= $options;
70
71 52
        $this->id = ++self::$_id;
72 52
    }
73
74 33
    public function isStart()
75 11
    {
76 33
        return $this->_start === null;
77 1
    }
78
79 31
    public function isEnd()
80 1
    {
81 31
        return $this->_end === null;
82
    }
83
84 14
     public function isValid(Context $context)
85
    {
86 14
        if ($this->_valid === null) {
87 13
            $this->validate($context);
88 13
        }
89
90 14
        return $this->_valid;
91
    }
92
93 11
    protected function validate(Context $context)
94
    {
95 11
        $this->setValid(
96 11
            $context->language === $this->rule->language &&
97 11
            $this->rule->validator->validate($context, $this->isEnd() ? [$this->name => Validator::CONTEXT_IN] : [])
98 11
        );
99 11
    }
100
101 14
    public function setValid($valid = true)
102
    {
103 14
        $this->_valid = $valid;
104
105 14
        if ($this->_end) {
106 11
            $this->_end->_valid = $this->_valid;
107 14
        } elseif ($this->_start) {
108 12
            $this->_start->_valid = $this->_valid;
109 12
        }
110 14
    }
111
112
    /**
113
     * @return Token|null|false
114
     */
115 30
    public function getStart()
116
    {
117 30
        return $this->_start;
118
    }
119
120
    /**
121
     * @param Token|null|false $start
122
     */
123 11 View Code Duplication
    public function setStart($start = null)
124
    {
125 11
        $this->_end   = null;
126 11
        $this->_start = $start;
127
128 11
        if ($start instanceof Token) {
129 11
            $this->_start->_length = null;
130 11
            $start->_end = $this;
131 11
        }
132 11
    }
133
134
    /**
135
     * @return Token|null|false
136
     */
137 38
    public function getEnd()
138
    {
139 38
        return $this->_end;
140
    }
141
142
    /**
143
     * @param Token|null|false $end
144
     */
145 46 View Code Duplication
    public function setEnd($end = null)
146
    {
147 46
        $this->_start  = null;
148 46
        $this->_end    = $end;
149 46
        $this->_length = null;
150
151 46
        if ($end instanceof Token) {
152 46
            $end->_start = $this;
153 46
        }
154 46
    }
155
156 2
    public function getLength()
157
    {
158 2
        if ($this->_length === null) {
159 2
            $this->_length = !$this->_end ? 0 : $this->_end->pos - $this->pos;
160 2
        }
161
162 2
        return $this->_length;
163
    }
164
165 11
    public function __get($name)
166
    {
167 11
        return $this->rule->$name;
168
    }
169
170
    /**
171
     * @param Context       $context
172
     * @param Language      $language
173
     * @param Result        $result
174
     * @param TokenIterator $tokens
175
     *
176
     * todo: Documentation
177
     *
178
     * @return bool Return true to continue processing, false to return already processed tokens.
179
     */
180 11
    public function process(Context $context, Language $language, Result $result, TokenIterator $tokens) {
181 11
        if(!$this->isValid($context)) {
182 3
            return true;
183
        }
184
185 11
        return $this->isStart() ?
186 11
            $this->processStart($context, $language, $result, $tokens) :
187 11
            $this->processEnd($context, $language, $result, $tokens);
188
    }
189
190 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...
191 10
        $result->append($this);
192 10
        $context->push($this);
193
194 10
        return true;
195
    }
196
197 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...
198 9
        if($this->_start) {
199 8
            $context->pop($this->_start);
200 8
        } else {
201 1
            if (($start = $context->find($this->name)) !== false) {
202 1
                $this->setStart($tokens[$start]);
203
204 1
                unset($context->stack[$start]);
205 1
            }
206
        }
207
208 9
        if (!$this->_start instanceof MetaToken) {
209 9
            $result->append($this);
210 9
        }
211
212 9
        return true;
213
    }
214
215 12
    public static function compare(Token $a, Token $b)
216
    {
217 12
        $multiplier = $a->isEnd() ? -1 : 1;
218
219 12
        if (($a->isStart() && $b->isEnd()) || ($a->isEnd() && $b->isStart())) {
220 1
            if ($a->getStart() == $b) {
221 1
                return 1;
222 1
            } elseif ($a->getEnd() == $b) {
223
                return -1;
224
            } else {
225 1
                return $multiplier;
226
            }
227 11
        } elseif (($rule = Helper::cmp($b->rule->priority, $a->rule->priority)) !== 0) {
228 10
            return $multiplier*$rule;
229
        }  else {
230 3
            return $multiplier*($a->id < $b->id ? -1 : 1);
231
        }
232
    }
233
}
234