1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the Behat Gherkin. |
5
|
|
|
* (c) Konstantin Kudryashov <[email protected]> |
6
|
|
|
* |
7
|
|
|
* For the full copyright and license information, please view the LICENSE |
8
|
|
|
* file that was distributed with this source code. |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
namespace Behat\Gherkin\Keywords; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* Gherkin keywords dumper. |
15
|
|
|
* |
16
|
|
|
* @author Konstantin Kudryashov <[email protected]> |
17
|
|
|
*/ |
18
|
|
|
class KeywordsDumper |
19
|
|
|
{ |
20
|
|
|
private $keywords; |
21
|
|
|
private $keywordsDumper; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Initializes dumper. |
25
|
|
|
* |
26
|
|
|
* @param KeywordsInterface $keywords Keywords instance |
27
|
|
|
*/ |
28
|
4 |
|
public function __construct(KeywordsInterface $keywords) |
29
|
|
|
{ |
30
|
4 |
|
$this->keywords = $keywords; |
31
|
4 |
|
$this->keywordsDumper = array($this, 'dumpKeywords'); |
32
|
4 |
|
} |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Sets keywords mapper function. |
36
|
|
|
* |
37
|
|
|
* Callable should accept 2 arguments (array $keywords and Boolean $isShort) |
38
|
|
|
* |
39
|
|
|
* @param callable $mapper Mapper function |
40
|
|
|
*/ |
41
|
1 |
|
public function setKeywordsDumperFunction($mapper) |
42
|
|
|
{ |
43
|
1 |
|
$this->keywordsDumper = $mapper; |
44
|
1 |
|
} |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Defaults keywords dumper. |
48
|
|
|
* |
49
|
|
|
* @param array $keywords Keywords list |
50
|
|
|
* @param Boolean $isShort Is short version |
51
|
|
|
* |
52
|
|
|
* @return string |
53
|
|
|
*/ |
54
|
3 |
|
public function dumpKeywords(array $keywords, $isShort) |
55
|
|
|
{ |
56
|
3 |
|
if ($isShort) { |
57
|
2 |
|
return 1 < count($keywords) ? '(' . implode('|', $keywords) . ')' : $keywords[0]; |
58
|
|
|
} |
59
|
|
|
|
60
|
1 |
|
return $keywords[0]; |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Dumps keyworded feature into string. |
65
|
|
|
* |
66
|
|
|
* @param string $language Keywords language |
67
|
|
|
* @param Boolean $short Dump short version |
68
|
|
|
* @param bool $excludeAsterisk |
69
|
|
|
* |
70
|
|
|
* @return string|array String for short version and array of features for extended |
71
|
|
|
*/ |
72
|
4 |
|
public function dump($language, $short = true, $excludeAsterisk = false) |
73
|
|
|
{ |
74
|
4 |
|
$this->keywords->setLanguage($language); |
75
|
4 |
|
$languageComment = ''; |
76
|
4 |
|
if ('en' !== $language) { |
77
|
3 |
|
$languageComment = "# language: $language\n"; |
78
|
|
|
} |
79
|
|
|
|
80
|
4 |
|
$keywords = explode('|', $this->keywords->getFeatureKeywords()); |
81
|
|
|
|
82
|
4 |
|
if ($short) { |
83
|
3 |
|
$keywords = call_user_func($this->keywordsDumper, $keywords, $short); |
84
|
|
|
|
85
|
3 |
|
return trim($languageComment . $this->dumpFeature($keywords, $short, $excludeAsterisk)); |
86
|
|
|
} |
87
|
|
|
|
88
|
1 |
|
$features = array(); |
89
|
1 |
|
foreach ($keywords as $keyword) { |
90
|
1 |
|
$keyword = call_user_func($this->keywordsDumper, array($keyword), $short); |
91
|
1 |
|
$features[] = trim($languageComment . $this->dumpFeature($keyword, $short, $excludeAsterisk)); |
92
|
|
|
} |
93
|
|
|
|
94
|
1 |
|
return $features; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Dumps feature example. |
99
|
|
|
* |
100
|
|
|
* @param string $keyword Item keyword |
101
|
|
|
* @param Boolean $short Dump short version? |
102
|
|
|
* |
103
|
|
|
* @return string |
104
|
|
|
*/ |
105
|
4 |
|
protected function dumpFeature($keyword, $short = true, $excludeAsterisk = false) |
106
|
|
|
{ |
107
|
|
|
$dump = <<<GHERKIN |
108
|
4 |
|
{$keyword}: Internal operations |
109
|
|
|
In order to stay secret |
110
|
|
|
As a secret organization |
111
|
|
|
We need to be able to erase past agents' memory |
112
|
|
|
|
113
|
|
|
|
114
|
|
|
GHERKIN; |
115
|
|
|
|
116
|
|
|
// Background |
117
|
4 |
|
$keywords = explode('|', $this->keywords->getBackgroundKeywords()); |
118
|
4 |
View Code Duplication |
if ($short) { |
|
|
|
|
119
|
3 |
|
$keywords = call_user_func($this->keywordsDumper, $keywords, $short); |
120
|
3 |
|
$dump .= $this->dumpBackground($keywords, $short, $excludeAsterisk); |
121
|
|
|
} else { |
122
|
1 |
|
$keyword = call_user_func($this->keywordsDumper, array($keywords[0]), $short); |
123
|
1 |
|
$dump .= $this->dumpBackground($keyword, $short, $excludeAsterisk); |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
// Scenario |
127
|
4 |
|
$keywords = explode('|', $this->keywords->getScenarioKeywords()); |
128
|
4 |
View Code Duplication |
if ($short) { |
|
|
|
|
129
|
3 |
|
$keywords = call_user_func($this->keywordsDumper, $keywords, $short); |
130
|
3 |
|
$dump .= $this->dumpScenario($keywords, $short, $excludeAsterisk); |
131
|
|
|
} else { |
132
|
1 |
|
foreach ($keywords as $keyword) { |
133
|
1 |
|
$keyword = call_user_func($this->keywordsDumper, array($keyword), $short); |
134
|
1 |
|
$dump .= $this->dumpScenario($keyword, $short, $excludeAsterisk); |
135
|
|
|
} |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
// Outline |
139
|
4 |
|
$keywords = explode('|', $this->keywords->getOutlineKeywords()); |
140
|
4 |
View Code Duplication |
if ($short) { |
|
|
|
|
141
|
3 |
|
$keywords = call_user_func($this->keywordsDumper, $keywords, $short); |
142
|
3 |
|
$dump .= $this->dumpOutline($keywords, $short, $excludeAsterisk); |
143
|
|
|
} else { |
144
|
1 |
|
foreach ($keywords as $keyword) { |
145
|
1 |
|
$keyword = call_user_func($this->keywordsDumper, array($keyword), $short); |
146
|
1 |
|
$dump .= $this->dumpOutline($keyword, $short, $excludeAsterisk); |
147
|
|
|
} |
148
|
|
|
} |
149
|
|
|
|
150
|
4 |
|
return $dump; |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* Dumps background example. |
155
|
|
|
* |
156
|
|
|
* @param string $keyword Item keyword |
157
|
|
|
* @param Boolean $short Dump short version? |
158
|
|
|
* |
159
|
|
|
* @return string |
160
|
|
|
*/ |
161
|
4 |
|
protected function dumpBackground($keyword, $short = true, $excludeAsterisk = false) |
162
|
|
|
{ |
163
|
|
|
$dump = <<<GHERKIN |
164
|
4 |
|
{$keyword}: |
165
|
|
|
|
166
|
|
|
GHERKIN; |
167
|
|
|
|
168
|
|
|
// Given |
169
|
4 |
|
$dump .= $this->dumpStep( |
170
|
4 |
|
$this->keywords->getGivenKeywords(), |
171
|
4 |
|
'there is agent A', |
172
|
4 |
|
$short, |
173
|
4 |
|
$excludeAsterisk |
174
|
|
|
); |
175
|
|
|
|
176
|
|
|
// And |
177
|
4 |
|
$dump .= $this->dumpStep( |
178
|
4 |
|
$this->keywords->getAndKeywords(), |
179
|
4 |
|
'there is agent B', |
180
|
4 |
|
$short, |
181
|
4 |
|
$excludeAsterisk |
182
|
|
|
); |
183
|
|
|
|
184
|
4 |
|
return $dump . "\n"; |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* Dumps scenario example. |
189
|
|
|
* |
190
|
|
|
* @param string $keyword Item keyword |
191
|
|
|
* @param Boolean $short Dump short version? |
192
|
|
|
* |
193
|
|
|
* @return string |
194
|
|
|
*/ |
195
|
4 |
|
protected function dumpScenario($keyword, $short = true, $excludeAsterisk = false) |
196
|
|
|
{ |
197
|
|
|
$dump = <<<GHERKIN |
198
|
4 |
|
{$keyword}: Erasing agent memory |
199
|
|
|
|
200
|
|
|
GHERKIN; |
201
|
|
|
|
202
|
|
|
// Given |
203
|
4 |
|
$dump .= $this->dumpStep( |
204
|
4 |
|
$this->keywords->getGivenKeywords(), |
205
|
4 |
|
'there is agent J', |
206
|
4 |
|
$short, |
207
|
4 |
|
$excludeAsterisk |
208
|
|
|
); |
209
|
|
|
|
210
|
|
|
// And |
211
|
4 |
|
$dump .= $this->dumpStep( |
212
|
4 |
|
$this->keywords->getAndKeywords(), |
213
|
4 |
|
'there is agent K', |
214
|
4 |
|
$short, |
215
|
4 |
|
$excludeAsterisk |
216
|
|
|
); |
217
|
|
|
|
218
|
|
|
// When |
219
|
4 |
|
$dump .= $this->dumpStep( |
220
|
4 |
|
$this->keywords->getWhenKeywords(), |
221
|
4 |
|
'I erase agent K\'s memory', |
222
|
4 |
|
$short, |
223
|
4 |
|
$excludeAsterisk |
224
|
|
|
); |
225
|
|
|
|
226
|
|
|
// Then |
227
|
4 |
|
$dump .= $this->dumpStep( |
228
|
4 |
|
$this->keywords->getThenKeywords(), |
229
|
4 |
|
'there should be agent J', |
230
|
4 |
|
$short, |
231
|
4 |
|
$excludeAsterisk |
232
|
|
|
); |
233
|
|
|
|
234
|
|
|
// But |
235
|
4 |
|
$dump .= $this->dumpStep( |
236
|
4 |
|
$this->keywords->getButKeywords(), |
237
|
4 |
|
'there should not be agent K', |
238
|
4 |
|
$short, |
239
|
4 |
|
$excludeAsterisk |
240
|
|
|
); |
241
|
|
|
|
242
|
4 |
|
return $dump . "\n"; |
243
|
|
|
} |
244
|
|
|
|
245
|
|
|
/** |
246
|
|
|
* Dumps outline example. |
247
|
|
|
* |
248
|
|
|
* @param string $keyword Item keyword |
249
|
|
|
* @param Boolean $short Dump short version? |
250
|
|
|
* |
251
|
|
|
* @return string |
252
|
|
|
*/ |
253
|
4 |
|
protected function dumpOutline($keyword, $short = true, $excludeAsterisk = false) |
254
|
|
|
{ |
255
|
|
|
$dump = <<<GHERKIN |
256
|
4 |
|
{$keyword}: Erasing other agents' memory |
257
|
|
|
|
258
|
|
|
GHERKIN; |
259
|
|
|
|
260
|
|
|
// Given |
261
|
4 |
|
$dump .= $this->dumpStep( |
262
|
4 |
|
$this->keywords->getGivenKeywords(), |
263
|
4 |
|
'there is agent <agent1>', |
264
|
4 |
|
$short, |
265
|
4 |
|
$excludeAsterisk |
266
|
|
|
); |
267
|
|
|
|
268
|
|
|
// And |
269
|
4 |
|
$dump .= $this->dumpStep( |
270
|
4 |
|
$this->keywords->getAndKeywords(), |
271
|
4 |
|
'there is agent <agent2>', |
272
|
4 |
|
$short, |
273
|
4 |
|
$excludeAsterisk |
274
|
|
|
); |
275
|
|
|
|
276
|
|
|
// When |
277
|
4 |
|
$dump .= $this->dumpStep( |
278
|
4 |
|
$this->keywords->getWhenKeywords(), |
279
|
4 |
|
'I erase agent <agent2>\'s memory', |
280
|
4 |
|
$short, |
281
|
4 |
|
$excludeAsterisk |
282
|
|
|
); |
283
|
|
|
|
284
|
|
|
// Then |
285
|
4 |
|
$dump .= $this->dumpStep( |
286
|
4 |
|
$this->keywords->getThenKeywords(), |
287
|
4 |
|
'there should be agent <agent1>', |
288
|
4 |
|
$short, |
289
|
4 |
|
$excludeAsterisk |
290
|
|
|
); |
291
|
|
|
|
292
|
|
|
// But |
293
|
4 |
|
$dump .= $this->dumpStep( |
294
|
4 |
|
$this->keywords->getButKeywords(), |
295
|
4 |
|
'there should not be agent <agent2>', |
296
|
4 |
|
$short, |
297
|
4 |
|
$excludeAsterisk |
298
|
|
|
); |
299
|
|
|
|
300
|
4 |
|
$keywords = explode('|', $this->keywords->getExamplesKeywords()); |
301
|
4 |
|
if ($short) { |
302
|
3 |
|
$keyword = call_user_func($this->keywordsDumper, $keywords, $short); |
303
|
|
|
} else { |
304
|
1 |
|
$keyword = call_user_func($this->keywordsDumper, array($keywords[0]), $short); |
305
|
|
|
} |
306
|
|
|
|
307
|
|
|
$dump .= <<<GHERKIN |
308
|
|
|
|
309
|
4 |
|
{$keyword}: |
310
|
|
|
| agent1 | agent2 | |
311
|
|
|
| D | M | |
312
|
|
|
|
313
|
|
|
GHERKIN; |
314
|
|
|
|
315
|
4 |
|
return $dump . "\n"; |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
/** |
319
|
|
|
* Dumps step example. |
320
|
|
|
* |
321
|
|
|
* @param string $keywords Item keyword |
322
|
|
|
* @param string $text Step text |
323
|
|
|
* @param Boolean $short Dump short version? |
324
|
|
|
* |
325
|
|
|
* @return string |
326
|
|
|
*/ |
327
|
4 |
|
protected function dumpStep($keywords, $text, $short = true, $excludeAsterisk = false) |
328
|
|
|
{ |
329
|
4 |
|
$dump = ''; |
330
|
|
|
|
331
|
4 |
|
$keywords = explode('|', $keywords); |
332
|
4 |
|
if ($short) { |
333
|
3 |
|
$keywords = array_map( |
334
|
|
|
function ($keyword) { |
335
|
3 |
|
return str_replace('<', '', $keyword); |
336
|
3 |
|
}, |
337
|
3 |
|
$keywords |
338
|
|
|
); |
339
|
3 |
|
$keywords = call_user_func($this->keywordsDumper, $keywords, $short); |
340
|
|
|
$dump .= <<<GHERKIN |
341
|
3 |
|
{$keywords} {$text} |
342
|
|
|
|
343
|
|
|
GHERKIN; |
344
|
|
|
} else { |
345
|
1 |
|
foreach ($keywords as $keyword) { |
346
|
1 |
|
if ($excludeAsterisk && '*' === $keyword) { |
347
|
|
|
continue; |
348
|
|
|
} |
349
|
|
|
|
350
|
1 |
|
$indent = ' '; |
351
|
1 |
|
if (false !== mb_strpos($keyword, '<', 0, 'utf8')) { |
352
|
|
|
$keyword = mb_substr($keyword, 0, -1, 'utf8'); |
353
|
|
|
$indent = ''; |
354
|
|
|
} |
355
|
1 |
|
$keyword = call_user_func($this->keywordsDumper, array($keyword), $short); |
356
|
|
|
$dump .= <<<GHERKIN |
357
|
1 |
|
{$keyword}{$indent}{$text} |
358
|
|
|
|
359
|
|
|
GHERKIN; |
360
|
|
|
} |
361
|
|
|
} |
362
|
|
|
|
363
|
4 |
|
return $dump; |
364
|
|
|
} |
365
|
|
|
} |
366
|
|
|
|
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.