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 classes like TableContext 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 TableContext, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
9 | class TableContext extends RawMinkContext |
||
10 | { |
||
11 | /** |
||
12 | * @Then /^I should see a table with "([^"]*)" in the "([^"]*)" column$/ |
||
13 | */ |
||
14 | public function iShouldSeeATableWithInTheNamedColumn($list, $column) |
||
15 | { |
||
16 | $cells = array_merge(array($column), $this->getFormater()->listToArray($list)); |
||
|
|||
17 | $expected = new TableNode(array_map(function($cell) { return [$cell]; }, $cells)); |
||
18 | |||
19 | $this->iShouldSeeTheFollowingTable($expected); |
||
20 | } |
||
21 | |||
22 | /** |
||
23 | * @Given /^I should see the following table:?$/ |
||
24 | */ |
||
25 | public function iShouldSeeTheFollowingTable($expected) |
||
55 | |||
56 | /** |
||
57 | * @Then /^I should see the following table portion:?$/ |
||
58 | */ |
||
59 | public function iShouldSeeTheFollowingTablePortion($expected) |
||
89 | |||
90 | /** |
||
91 | * @Then /^I should see a table with ([^"]*) rows$/ |
||
92 | * @Then /^I should see a table with ([^"]*) row$/ |
||
93 | */ |
||
94 | public function iShouldSeeATableWithRows($nbr) |
||
119 | |||
120 | /** |
||
121 | * @Then /^I should see a table$/ |
||
122 | */ |
||
123 | public function iShouldSeeATable() |
||
133 | |||
134 | protected function extractColumns(array $headers, array $table) |
||
168 | |||
169 | protected function findTables() |
||
170 | { |
||
171 | $tables = $this->getSession()->getPage()->findAll('css', 'table'); |
||
172 | $result = array(); |
||
173 | |||
174 | foreach ($tables as $table) { |
||
175 | $node = array(); |
||
176 | $head = $table->find('css', 'thead'); |
||
177 | $body = $table->find('css', 'tbody'); |
||
178 | $foot = $table->find('css', 'tfoot'); |
||
179 | if (null !== $head || null !== $body || null !== $foot) { |
||
180 | $this->extractDataFromPart($head, $node); |
||
181 | $this->extractDataFromPart($body, $node); |
||
182 | $this->extractDataFromPart($foot, $node); |
||
183 | } else { |
||
184 | $this->extractDataFromPart($table, $node); |
||
185 | } |
||
186 | $result[] = $node; |
||
187 | } |
||
188 | |||
189 | return $result; |
||
190 | } |
||
191 | |||
192 | protected function extractDataFromPart($part, &$array) |
||
193 | { |
||
194 | if (null === $part) { |
||
195 | |||
196 | return; |
||
197 | } |
||
198 | |||
199 | foreach ($part->findAll('css', 'tr') as $row) { |
||
200 | $array[] = $this->extractDataFromRow($row); |
||
201 | } |
||
202 | } |
||
203 | |||
204 | protected function extractDataFromRow($row) |
||
215 | |||
216 | protected function reorderArrayKeys(array $subject) |
||
230 | |||
231 | protected function getAsserter() |
||
235 | |||
236 | protected function getFormater() |
||
240 | } |
||
241 |
This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.
To visualize
will produce issues in the first and second line, while this second example
will produce no issues.