Completed
Push — master ( e7ab98...751609 )
by Shcherbak
02:45
created

ClassPattern::__invoke()   B

Complexity

Conditions 7
Paths 32

Size

Total Lines 52
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 27
CRAP Score 7.0022

Importance

Changes 0
Metric Value
dl 0
loc 52
ccs 27
cts 28
cp 0.9643
rs 7.2396
c 0
b 0
f 0
cc 7
eloc 29
nc 32
nop 1
crap 7.0022

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
  declare(strict_types=1);
4
5
  namespace Funivan\PhpTokenizer\Pattern\Patterns;
6
7
  use Funivan\PhpTokenizer\QuerySequence\QuerySequence;
8
  use Funivan\PhpTokenizer\Strategy\Possible;
9
  use Funivan\PhpTokenizer\Strategy\QueryStrategy;
10
  use Funivan\PhpTokenizer\Strategy\Strict;
11
  use Funivan\PhpTokenizer\Token;
12
13
  /**
14
   * PatternMatcher used to finding classes in tour source code
15
   *
16
   */
17
  class ClassPattern implements PatternInterface {
18
19
    /**
20
     * Result of this pattern will be body of the class
21
     */
22
    const OUTPUT_BODY = 1;
23
24
    /**
25
     * Result of this pattern will be full class
26
     */
27
    const OUTPUT_FULL = 2;
28
29
30
    /**
31
     * @var QueryStrategy
32
     */
33
    private $nameQuery;
34
35
    /**
36
     * @var callable
37
     */
38
    private $docCommentChecker;
39
40
    /**
41
     * @var callable[]
42
     */
43
    private $modifierChecker;
44
45
    /**
46
     * @var int
47
     */
48
    private $outputType = self::OUTPUT_FULL;
49
50
51
    /**
52
     * By default we search for classes with any name
53
     */
54 57
    public function __construct() {
55 57
      $this->nameQuery = Strict::create()->valueLike('!.+!');
56 57
      $this->withPossibleDocComment();
57 57
      $this->withAnyModifier();
58 57
    }
59
60
61
    /**
62
     * @param QueryStrategy|string $name
63
     * @return $this
64
     */
65 15
    public function withName($name): self {
66 15
      if (is_string($name)) {
67 9
        $this->nameQuery = Strict::create()->valueIs($name);
68 9
      } elseif ($name instanceof QueryStrategy) {
69 6
        $this->nameQuery = $name;
70
      } else {
71 3
        throw new \InvalidArgumentException('Expect string or QueryInterface');
72
      }
73
74 12
      return $this;
75
    }
76
77
78
    /**
79
     * @return $this
80
     */
81 3
    public function withDocComment(): self {
82
      $this->docCommentChecker = function (Token $comment, QuerySequence $q) {
83 3
        if ($comment->getType() !== T_DOC_COMMENT) {
84 3
          $q->setValid(false);
85
        }
86 3
      };
87 3
      return $this;
88
    }
89
90
91
    /**
92
     * @return $this
93
     */
94 57
    public function withPossibleDocComment(): self {
95
      $this->docCommentChecker = function () {
96
97 48
      };
98 57
      return $this;
99
    }
100
101
102
    /**
103
     * @return $this
104
     */
105 3
    public function withoutDocComment(): self {
106
      $this->docCommentChecker = function (Token $comment, QuerySequence $q) {
107 3
        if ($comment->getType() === T_DOC_COMMENT) {
108 3
          $q->setValid(false);
109
        }
110 3
      };
111 3
      return $this;
112
    }
113
114
115
    /**
116
     * @return $this
117
     */
118 3
    public function outputBody(): self {
119 3
      $this->outputType = self::OUTPUT_BODY;
120 3
      return $this;
121
    }
122
123
124
    /**
125
     * @return $this
126
     */
127 18
    public function outputFull(): self {
128 18
      $this->outputType = self::OUTPUT_FULL;
129 18
      return $this;
130
    }
131
132
133
    /**
134
     * @inheritdoc
135
     */
136 54
    public function __invoke(QuerySequence $querySequence) {
137
138 54
      $comment = $querySequence->process(Possible::create()->typeIs(T_DOC_COMMENT));
139
140 54
      $querySequence->possible(T_WHITESPACE);
141 54
      $modifier = $querySequence->process(Possible::create()->valueIs([
142 54
        'abstract',
143
        'final',
144
      ]));
145
146 54
      $querySequence->possible(T_WHITESPACE);
147 54
      $start = $querySequence->strict('class');
148 54
      $querySequence->strict(T_WHITESPACE);
149 54
      $querySequence->process($this->nameQuery);
150 54
      $startClassBody = $querySequence->search('{');
151 54
      $querySequence->moveToToken($startClassBody);
152 54
      $body = $querySequence->section('{', '}');
153
154 54
      if ($modifier->isValid()) {
155 21
        $start = $modifier;
156
      }
157
158 54
      if ($comment->isValid()) {
159 15
        $start = $comment;
160
      }
161
162 54
      $docCommentChecker = $this->docCommentChecker;
163 54
      $docCommentChecker($comment, $querySequence);
164
165
166 54
      foreach ($this->modifierChecker as $checker) {
167 54
        $checker($modifier, $querySequence);
168
      }
169
170
171 54
      if (!$querySequence->isValid()) {
172 54
        return null;
173
      }
174
175
      # self::OUTPUT_FULL
176 51
      $lastBodyToken = $body->getLast();
177 51
      if ($lastBodyToken === null) {
178
        return null;
179
      }
180
181 51
      if ($this->outputType === self::OUTPUT_BODY) {
182 3
        return $body->extractItems(1, -1);
183
      }
184
185
186 48
      return $querySequence->getCollection()->extractByTokens($start, $lastBodyToken);
187
    }
188
189
190
    /**
191
     * @return $this
192
     */
193 57
    public function withAnyModifier(): self {
194 57
      $this->modifierChecker = [];
195
      $this->modifierChecker[] = function () {
196 54
      };
197 57
      return $this;
198
    }
199
200
201
    /**
202
     * @param string $modifier
203
     * @return $this
204
     */
205 6
    public function withModifier(string $modifier): self {
206
207
      $this->modifierChecker[] = function (Token $token, QuerySequence $q) use ($modifier) {
208 6
        if ($token->getValue() !== $modifier) {
209 6
          $q->setValid(false);
210
        }
211 6
      };
212
213
214 6
      return $this;
215
    }
216
217
218
    /**
219
     * @param string $modifier
220
     * @return $this
221
     */
222
    public function withoutModifier(string $modifier): self {
223
224 3
      $this->modifierChecker[] = function (Token $token, QuerySequence $q) use ($modifier) {
225 3
        if ($token->getValue() === $modifier) {
226 3
          $q->setValid(false);
227
        }
228 3
      };
229 3
      return $this;
230
    }
231
232
233
  }