These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php namespace Tarsana\Functional; |
||
2 | /** |
||
3 | * This script parses the source files using [dox](https://github.com/tj/dox) |
||
4 | * and generates the unit tests and documentation files. |
||
5 | */ |
||
6 | require __DIR__ . '/vendor/autoload.php'; |
||
7 | |||
8 | /** |
||
9 | * Custom Types: |
||
10 | * DoxBlock :: { |
||
11 | * tags: [{ |
||
12 | * type: String, |
||
13 | * string: String, |
||
14 | * types: [String], |
||
15 | * name: String, |
||
16 | * description: String |
||
17 | * ... |
||
18 | * }], |
||
19 | * description: { |
||
20 | * full: String, |
||
21 | * summary: String, |
||
22 | * body: String |
||
23 | * }, |
||
24 | * code: String, |
||
25 | * ctx: { |
||
26 | * type: String, |
||
27 | * name: String, |
||
28 | * ... |
||
29 | * } |
||
30 | * isPrivate: |
||
31 | * isEvent: |
||
32 | * isConstructor: |
||
33 | * line: |
||
34 | * ignore: |
||
35 | * } |
||
36 | * |
||
37 | * Block :: { |
||
38 | * type: file|function|class|method |
||
39 | * name: String // DoxBlock.ctx.name |
||
40 | * params: [{type: String, name: String}] |
||
41 | * return: String |
||
42 | * signatures: [String] |
||
43 | * description: String |
||
44 | * summary: String |
||
45 | * internal: Boolean |
||
46 | * ignore: Boolean |
||
47 | * code: String |
||
48 | * } |
||
49 | * |
||
50 | * Operation :: { |
||
51 | * name: String, |
||
52 | * signature: String |
||
53 | * } |
||
54 | * |
||
55 | * Module :: { |
||
56 | * path: String |
||
57 | * name: String |
||
58 | * docsPath: String |
||
59 | * testsPath: String |
||
60 | * blocks: [Block] |
||
61 | * docs: String |
||
62 | * tests: String |
||
63 | * testsFooter: String |
||
64 | * streamOperations: String |
||
65 | * streamMethods: String |
||
66 | * } |
||
67 | */ |
||
68 | |||
69 | /** |
||
70 | * The entry point. |
||
71 | * |
||
72 | * @signature [String] -> IO |
||
73 | * @param array $modules |
||
74 | * @return void |
||
75 | */ |
||
76 | function build_main($modules) { |
||
77 | build_init_stream_operations(); |
||
78 | each(_f('build_module'), $modules); |
||
79 | build_close_stream_operations(); |
||
80 | } |
||
81 | |||
82 | /** |
||
83 | * Writes the header of the stream operations file. |
||
84 | * |
||
85 | * @signature IO |
||
86 | * @return void |
||
87 | */ |
||
88 | function build_init_stream_operations() { |
||
89 | file_put_contents( |
||
90 | 'src/Internal/_stream_operations.php', |
||
91 | "<?php\n\nuse Tarsana\Functional as F;\n\nreturn F\map(F\apply(F\_f('_stream_operation')), [\n\t['then', 'Function -> Any -> Any', F\_f('_stream_then')],\n" |
||
92 | ); |
||
93 | file_put_contents( |
||
94 | 'docs/stream-methods.md', |
||
95 | "# Stream Methods" |
||
96 | ); |
||
97 | } |
||
98 | |||
99 | /** |
||
100 | * Writes the footer of the stream operations file. |
||
101 | * |
||
102 | * @signature IO |
||
103 | * @return void |
||
104 | */ |
||
105 | function build_close_stream_operations() { |
||
106 | file_put_contents( |
||
107 | 'src/Internal/_stream_operations.php', |
||
108 | "\n]);\n", FILE_APPEND |
||
109 | ); |
||
110 | } |
||
111 | |||
112 | /** |
||
113 | * Extracts the modules files from composer.json. |
||
114 | * |
||
115 | * @signature [String] |
||
116 | * @return array |
||
117 | */ |
||
118 | function get_modules() { |
||
119 | $composer = json_decode(file_get_contents(__DIR__.'/composer.json')); |
||
120 | return $composer->autoload->files; |
||
121 | } |
||
122 | |||
123 | /** |
||
124 | * Generates unit tests and documentation for a module. |
||
125 | * |
||
126 | * @signature String -> IO |
||
127 | * @param string $path |
||
128 | * @return void |
||
129 | */ |
||
130 | function build_module($path) { |
||
131 | apply(process_of([ |
||
132 | 'module_of', |
||
133 | 'generate_docs', |
||
134 | 'generate_tests', |
||
135 | 'generate_stream_operations', |
||
136 | 'generate_stream_methods', |
||
137 | 'write_module' |
||
138 | ]), [$path]); |
||
139 | } |
||
140 | |||
141 | /** |
||
142 | * Writes the module's docs and tests. |
||
143 | * |
||
144 | * @signature Module -> IO |
||
145 | * @param object $module |
||
146 | * @return void |
||
147 | */ |
||
148 | function write_module($module) { |
||
149 | View Code Duplication | if ($module->docs) { |
|
150 | $docsDir = dirname($module->docsPath); |
||
151 | if (!is_dir($docsDir)) |
||
152 | mkdir($docsDir, 0777, true); |
||
153 | file_put_contents($module->docsPath, $module->docs); |
||
154 | } |
||
155 | View Code Duplication | if ($module->tests) { |
|
156 | $testsDir = dirname($module->testsPath); |
||
157 | if (!is_dir($testsDir)) |
||
158 | mkdir($testsDir, 0777, true); |
||
159 | file_put_contents($module->testsPath, $module->tests); |
||
160 | } |
||
161 | if ($module->streamOperations) { |
||
162 | file_put_contents('src/Internal/_stream_operations.php', $module->streamOperations, FILE_APPEND); |
||
163 | } |
||
164 | if ($module->streamMethods) { |
||
165 | file_put_contents('docs/stream-methods.md', $module->streamMethods, FILE_APPEND); |
||
166 | } |
||
167 | } |
||
168 | |||
169 | /** |
||
170 | * Creates a module from a path. |
||
171 | * |
||
172 | * @signature String -> Module |
||
173 | * @param string $path |
||
174 | * @return object |
||
175 | */ |
||
176 | function module_of($path) { |
||
177 | return apply(process_of([ |
||
178 | 'fill_name', |
||
179 | 'fill_docs_path', |
||
180 | 'fill_tests_path', |
||
181 | 'fill_blocks' |
||
182 | ]), [(object)['path' => $path]]); |
||
183 | } |
||
184 | |||
185 | /** |
||
186 | * Fills documentation file path based on source file path. |
||
187 | * 'src/xxx.php' -> 'docs/xxx.md' |
||
188 | * |
||
189 | * @signature Module -> Module |
||
190 | * @param object $module |
||
191 | * @return object |
||
192 | */ |
||
193 | function fill_docs_path($module) { |
||
194 | $module->docsPath = replace(['src', '.php'], ['docs', '.md'], $module->path); |
||
195 | return $module; |
||
196 | } |
||
197 | |||
198 | /** |
||
199 | * Fills tests file path based on source file path. |
||
200 | * 'src/xxx.php' -> 'tests/xxxTest.php' |
||
201 | * |
||
202 | * @signature Module -> Module |
||
203 | * @param object $module |
||
204 | * @return object |
||
205 | */ |
||
206 | function fill_tests_path($module) { |
||
207 | $name = ucfirst(camelCase($module->name)); |
||
208 | $dir = 'tests' . remove(3, dirname($module->path)); |
||
209 | $module->testsPath = "{$dir}/{$name}Test.php"; |
||
210 | return $module; |
||
211 | } |
||
212 | |||
213 | /** |
||
214 | * Fills the name of the Module based on the path. |
||
215 | * 'src/xxx/aaa.php' -> 'aaa' |
||
216 | * |
||
217 | * @signature Module -> Module |
||
218 | * @param object $module |
||
219 | * @return object |
||
220 | */ |
||
221 | function fill_name($module) { |
||
222 | $module->name = apply(pipe(split('/'), last(), split('.'), head()), [$module->path]); |
||
223 | return $module; |
||
224 | } |
||
225 | |||
226 | /** |
||
227 | * Fills the blocks of the Module based on the path. |
||
228 | * |
||
229 | * @signature Module -> Module |
||
230 | * @param array $module |
||
231 | * @return array |
||
232 | */ |
||
233 | function fill_blocks($module) { |
||
234 | $module->blocks = apply(pipe( |
||
235 | prepend('dox -r < '), // "dox -r < src/...php" |
||
236 | 'shell_exec', // "[{...}, ...]" |
||
237 | 'json_decode', // [DoxBlock] |
||
238 | map(_f('make_block')) |
||
239 | // sort() |
||
240 | ), [$module->path]); |
||
241 | return $module; |
||
242 | } |
||
243 | |||
244 | /** |
||
245 | * Converts a DoxBlock to a Block. |
||
246 | * |
||
247 | * @signature DoxBlock -> Block |
||
248 | * @param object $doxBlock |
||
249 | * @return object |
||
250 | */ |
||
251 | function make_block($doxBlock) { |
||
252 | $tags = groupBy(get('name'), tags_of($doxBlock)); |
||
253 | |||
254 | $type = 'function'; |
||
255 | if (has('file', $tags)) $type = 'file'; |
||
256 | if (has('class', $tags)) $type = 'class'; |
||
257 | if (has('method', $tags)) $type = 'method'; |
||
258 | |||
259 | $params = map(function($tag){ |
||
260 | $parts = split(' ', get('value', $tag)); |
||
261 | return [ |
||
262 | 'type' => $parts[0], |
||
263 | 'name' => $parts[1] |
||
264 | ]; |
||
265 | }, get('param', $tags) ?: []); |
||
266 | |||
267 | $return = getPath(['return', 0, 'value'], $tags); |
||
268 | $signatures = get('signature', $tags); |
||
269 | if ($signatures) |
||
270 | $signatures = map(get('value'), $signatures); |
||
271 | return (object) [ |
||
272 | 'type' => $type, |
||
273 | 'name' => getPath(['ctx', 'name'], $doxBlock), |
||
274 | 'params' => $params, |
||
275 | 'return' => $return, |
||
276 | 'signatures' => $signatures, |
||
277 | 'description' => getPath(['description', 'full'], $doxBlock), |
||
278 | 'summary' => getPath(['description', 'summary'], $doxBlock), |
||
279 | 'internal' => has('internal', $tags), |
||
280 | 'ignore' => has('ignore', $tags), |
||
281 | 'stream' => has('stream', $tags) |
||
282 | // 'code' => get('code', $doxBlock) |
||
283 | ]; |
||
284 | } |
||
285 | |||
286 | /** |
||
287 | * Returns an array of tags, each having a name and a value. |
||
288 | * |
||
289 | * @signature DoxBlock -> [{name: String, value: String}] |
||
290 | * @param object $doxBlock |
||
291 | * @return array |
||
292 | */ |
||
293 | function tags_of($doxBlock) { |
||
294 | if ($doxBlock->tags) |
||
295 | return map(function($tag){ |
||
296 | return (object) [ |
||
297 | 'name' => $tag->type, |
||
298 | 'value' => $tag->string |
||
299 | ]; |
||
300 | }, $doxBlock->tags); |
||
301 | return []; |
||
302 | } |
||
303 | |||
304 | /** |
||
305 | * Generates documentation contents for a module. |
||
306 | * |
||
307 | * @signature Module -> Module |
||
308 | * @param object $module |
||
309 | * @return object |
||
310 | */ |
||
311 | function generate_docs($module) { |
||
312 | $module->docs = ''; |
||
313 | if (startsWith('_', $module->name)) |
||
314 | return $module; |
||
315 | return apply(process_of([ |
||
316 | 'generate_docs_header', |
||
317 | 'generate_docs_sommaire', |
||
318 | 'generate_docs_contents' |
||
319 | ]), [$module]); |
||
320 | } |
||
321 | |||
322 | /** |
||
323 | * Generates documentation header. |
||
324 | * |
||
325 | * @signature Module -> Module |
||
326 | * @param object $module |
||
327 | * @return object |
||
328 | */ |
||
329 | function generate_docs_header($module) { |
||
330 | $name = $module->name; |
||
331 | $description = get('description', head($module->blocks)); |
||
332 | $module->docs .= "#{$name}\n\n{$description}\n\n"; |
||
333 | return $module; |
||
334 | } |
||
335 | |||
336 | /** |
||
337 | * Generates documentation table of contents. |
||
338 | * |
||
339 | * @signature Module -> Module |
||
340 | * @param object $module |
||
341 | * @return object |
||
342 | */ |
||
343 | View Code Duplication | function generate_docs_sommaire($module) { |
|
344 | $blocks = filter ( |
||
345 | satisfiesAll(['ignore' => not(), 'internal' => not(), 'type' => equals('function')]), |
||
346 | $module->blocks |
||
347 | ); |
||
348 | $items = map(_f('generate_docs_sommaire_item'), $blocks); |
||
349 | $module->docs .= join('', $items); |
||
350 | return $module; |
||
351 | } |
||
352 | |||
353 | /** |
||
354 | * Generates an item of the documentation's table of contents. |
||
355 | * |
||
356 | * @signature Block -> String |
||
357 | * @param object $block |
||
358 | * @return string |
||
359 | */ |
||
360 | function generate_docs_sommaire_item($block) { |
||
361 | $title = get('name', $block); |
||
362 | $link = lowerCase($title); |
||
363 | return "- [{$title}](#{$link}) - {$block->summary}\n\n"; |
||
364 | } |
||
365 | |||
366 | /** |
||
367 | * Generates documentation contents. |
||
368 | * |
||
369 | * @signature Module -> Module |
||
370 | * @param object $module |
||
371 | * @return object |
||
372 | */ |
||
373 | View Code Duplication | function generate_docs_contents($module) { |
|
374 | $blocks = filter ( |
||
375 | satisfiesAll(['ignore' => not(), 'internal' => not()]), |
||
376 | $module->blocks |
||
377 | ); |
||
378 | $contents = map(_f('generate_docs_contents_item'), $blocks); |
||
379 | $module->docs .= join('', $contents); |
||
380 | return $module; |
||
381 | } |
||
382 | |||
383 | /** |
||
384 | * Generates an item of the documentation's contents. |
||
385 | * |
||
386 | * @signature Block -> String |
||
387 | * @param object $block |
||
388 | * @return string |
||
389 | */ |
||
390 | function generate_docs_contents_item($block) { |
||
391 | if ($block->type != 'function') |
||
392 | return ''; |
||
393 | $params = join(', ', map(pipe(values(), join(' ')), get('params', $block))); |
||
394 | $return = get('return', $block); |
||
395 | $prototype = "```php\n{$block->name}({$params}) : {$return}\n```\n\n"; |
||
396 | $signature = ''; |
||
397 | $blockSignature = join("\n", $block->signatures); |
||
398 | if ($blockSignature) |
||
399 | $signature = "```\n{$blockSignature}\n```\n\n"; |
||
400 | return "# {$block->name}\n\n{$prototype}{$signature}{$block->description}\n\n"; |
||
401 | } |
||
402 | |||
403 | /** |
||
404 | * Generates tests contents for a module. |
||
405 | * |
||
406 | * @signature Module -> Module |
||
407 | * @param object $module |
||
408 | * @return object |
||
409 | */ |
||
410 | function generate_tests($module) { |
||
411 | $module->tests = ''; |
||
412 | $module->testsFooter = ''; |
||
413 | return apply(process_of([ |
||
414 | 'generate_tests_header', |
||
415 | 'generate_tests_contents', |
||
416 | 'generate_tests_footer' |
||
417 | ]), [$module]); |
||
418 | } |
||
419 | |||
420 | /** |
||
421 | * Generates module's tests header. |
||
422 | * |
||
423 | * @signature Module -> Module |
||
424 | * @param object $module |
||
425 | * @return object |
||
426 | */ |
||
427 | function generate_tests_header($module) { |
||
428 | $namespace = "Tarsana\UnitTests\Functional"; |
||
429 | $additionalNamespace = replace("/", "\\", remove(6, dirname($module->testsPath))); |
||
430 | if ($additionalNamespace) |
||
431 | $namespace .= "\\" . $additionalNamespace; |
||
432 | $name = remove(-4, last(split("/", $module->testsPath))); |
||
433 | $module->tests .= "<?php namespace {$namespace};\n\nuse Tarsana\Functional as F;\n\nclass {$name} extends \Tarsana\UnitTests\Functional\UnitTest {\n"; |
||
434 | return $module; |
||
435 | } |
||
436 | |||
437 | /** |
||
438 | * Generates module's tests contents. |
||
439 | * |
||
440 | * @signature Module -> Module |
||
441 | * @param object $module |
||
442 | * @return object |
||
443 | */ |
||
444 | function generate_tests_contents($module) { |
||
445 | $blocks = filter ( |
||
446 | satisfiesAll(['ignore' => not()]), |
||
447 | $module->blocks |
||
448 | ); |
||
449 | $contents = join("\n", map(function($block) use($module) { |
||
450 | return generate_tests_contents_item($block, $module); |
||
451 | }, $blocks)); |
||
452 | if (trim($contents) != '') |
||
453 | $module->tests .= $contents; |
||
454 | else |
||
455 | $module->tests = ''; |
||
456 | return $module; |
||
457 | } |
||
458 | |||
459 | /** |
||
460 | * Generates a test for a module. |
||
461 | * |
||
462 | * @signature Block -> Module -> String |
||
463 | * @param object $block |
||
464 | * @param object $module |
||
465 | * @return string |
||
466 | */ |
||
467 | function generate_tests_contents_item($block, $module) { |
||
468 | if ($block->type != 'function') |
||
469 | return ''; |
||
470 | |||
471 | $code = apply(pipe( |
||
472 | _f('code_from_description'), |
||
473 | chunks("\"\"''{}[]()", "\n"), |
||
474 | map(function($part) use($module) { |
||
475 | return add_assertions($part, $module); |
||
476 | }), |
||
477 | filter(pipe('trim', notEq(''))), |
||
478 | chain(split("\n")), |
||
479 | map(prepend("\t\t")), |
||
480 | join("\n") |
||
481 | ), [$block]); |
||
482 | |||
483 | if ('' == trim($code)) |
||
484 | return ''; |
||
485 | return prepend("\tpublic function test_{$block->name}() {\n", |
||
486 | append("\n\t}\n", $code) |
||
487 | ); |
||
488 | } |
||
489 | |||
490 | /** |
||
491 | * Extracts the code snippet from the description of a block. |
||
492 | * |
||
493 | * @signature Block -> String |
||
494 | * @param object $block |
||
495 | * @return string |
||
496 | */ |
||
497 | function code_from_description($block) { |
||
498 | $description = get('description', $block); |
||
499 | if (!contains('```php', $description)) |
||
500 | return ''; |
||
501 | $code = remove(7 + indexOf('```php', $description), $description); |
||
502 | return remove(-4, trim($code)); |
||
503 | } |
||
504 | |||
505 | /** |
||
506 | * Adds assertions to a part of the code. |
||
507 | * |
||
508 | * @signature String -> String |
||
509 | * @param string $part |
||
510 | * @return string |
||
511 | */ |
||
512 | function add_assertions($part, $module) { |
||
513 | if (contains('; //=> ', $part)) { |
||
514 | $pieces = split('; //=> ', $part); |
||
515 | $part = "\$this->assertEquals({$pieces[1]}, {$pieces[0]});"; |
||
516 | } |
||
517 | elseif (contains('; // throws ', $part)) { |
||
518 | $pieces = split('; // throws ', $part); |
||
519 | $variables = match('/ \$[0-9a-zA-Z_]+/', $pieces[0]); |
||
520 | $use = ''; |
||
521 | if (length($variables)) { |
||
522 | $variables = join(', ', map('trim', $variables)); |
||
523 | $use = "use({$variables}) "; |
||
524 | } |
||
525 | return "\$this->assertErrorThrown(function() {$use}{\n\t$pieces[0]; \n},\n{$pieces[1]});"; |
||
526 | } |
||
527 | elseif (startsWith('class ', $part) || startsWith('function ', $part)) { |
||
528 | $module->testsFooter .= $part . "\n\n"; |
||
529 | $part = ''; |
||
530 | } |
||
531 | return $part; |
||
532 | } |
||
533 | |||
534 | /** |
||
535 | * Generates module's tests footer. |
||
536 | * |
||
537 | * @signature Module -> Module |
||
538 | * @param object $module |
||
539 | * @return object |
||
540 | */ |
||
541 | function generate_tests_footer($module) { |
||
542 | if ($module->tests) |
||
543 | $module->tests .= "}\n\n{$module->testsFooter}"; |
||
544 | return $module; |
||
545 | } |
||
546 | |||
547 | /** |
||
548 | * Generates module's stream operations. |
||
549 | * |
||
550 | * @signature Module -> Module |
||
551 | * @param array $module |
||
552 | * @return array |
||
553 | */ |
||
554 | function generate_stream_operations($module) { |
||
555 | $blocks = filter ( |
||
556 | satisfiesAll(['ignore' => equals(false), 'stream' => equals(true)]), |
||
557 | $module->blocks |
||
558 | ); |
||
559 | $operations = map(_f('stream_operation_declaration'), chain(_f('stream_operations_of_block'), $blocks)); |
||
560 | $module->streamOperations = join("", $operations); |
||
561 | return $module; |
||
562 | } |
||
563 | |||
564 | /** |
||
565 | * Gets stream operations from a block. |
||
566 | * |
||
567 | * @signature Block -> [Operation] |
||
568 | * @param object $block |
||
569 | * @return string |
||
570 | */ |
||
571 | function stream_operations_of_block($block) { |
||
572 | return map(function($signature) use($block) { |
||
573 | return (object) [ |
||
574 | 'name' => $block->name, |
||
575 | 'signature' => normalize_signature($signature) |
||
576 | ]; |
||
577 | }, get('signatures', $block)); |
||
578 | } |
||
579 | |||
580 | /** |
||
581 | * Converts a formal signature to a stream signature. |
||
582 | * [a] becomes List |
||
583 | * {k: v} becomes Array|Object |
||
584 | * (a -> b) becomes Function |
||
585 | * * becomes Any |
||
586 | * |
||
587 | * @signature String -> String |
||
588 | * @param string $signature |
||
589 | * @return string |
||
590 | */ |
||
591 | function normalize_signature($signature) { |
||
592 | // This is not the best way to do it :P |
||
593 | return join(' -> ', map(pipe( |
||
594 | regReplace('/Maybe\([a-z][^\)]*\)/', 'Any'), |
||
595 | regReplace('/Maybe\(([^\)]+)\)/', '$1|Null'), |
||
596 | regReplace('/\([^\)]+\)/', 'Function'), |
||
597 | regReplace('/\[[^\]]+\]/', 'List'), |
||
598 | regReplace('/\{[^\}]+\}/', 'Object|Array'), |
||
599 | regReplace('/^.$/', 'Any'), |
||
600 | regReplace('/[\(\)\[\]\{\}]/', '') |
||
601 | ), chunks('(){}', ' -> ', $signature))); |
||
602 | } |
||
603 | |||
604 | /** |
||
605 | * Converts a stream operation to declaration array. |
||
606 | * |
||
607 | * @signature Operation -> String |
||
608 | * @param object $operation |
||
609 | * @return string |
||
610 | */ |
||
611 | function stream_operation_declaration($operation) { |
||
612 | $name = rtrim($operation->name, '_'); |
||
613 | return "\t['{$name}', '{$operation->signature}', F\\{$operation->name}()],\n"; |
||
614 | } |
||
615 | |||
616 | /** |
||
617 | * Generates module's stream methods documentation. |
||
618 | * |
||
619 | * @signature Module -> Module |
||
620 | * @param array $module |
||
621 | * @return array |
||
622 | */ |
||
623 | function generate_stream_methods($module) { |
||
624 | $blocks = filter ( |
||
625 | satisfiesAll(['ignore' => equals(false), 'stream' => equals(true)]), |
||
626 | $module->blocks |
||
627 | ); |
||
628 | $methods = map(stream_method_link($module->name), $blocks); |
||
629 | $module->streamMethods = "\n\n## {$module->name}\n\n" . join("\n", $methods); |
||
630 | return $module; |
||
631 | } |
||
632 | |||
633 | /** |
||
634 | * Gets an element of the stream methods list. |
||
635 | * |
||
636 | * @signature String -> Block -> String |
||
637 | * @param string $moduleName |
||
638 | * @param object $block |
||
639 | * @return string |
||
640 | */ |
||
641 | function stream_method_link() { |
||
642 | static $curried = false; |
||
643 | $curried = $curried ?: curry(function($moduleName, $block) { |
||
644 | return "- [{$block->name}](https://github.com/tarsana/functional/blob/master/docs/{$moduleName}.md#{$block->name}) - {$block->summary}\n"; |
||
645 | }); |
||
646 | return _apply($curried, func_get_args()); |
||
647 | } |
||
648 | |||
649 | /** |
||
650 | * process_of(['f1', 'f2']) == pipe(_f('f1'), _f('f2')); |
||
651 | * |
||
652 | * @signature [String] -> Function |
||
653 | * @param array $fns |
||
654 | * @return callable |
||
655 | */ |
||
656 | function process_of($fns) { |
||
657 | return apply(_f('pipe'), map(_f('_f'), $fns)); |
||
658 | } |
||
659 | |||
660 | /** |
||
661 | * Dump a variable and returns it. |
||
662 | * |
||
663 | * @signature a -> a |
||
664 | * @param mixed $something |
||
665 | * @return mixed |
||
666 | */ |
||
667 | function log() { |
||
668 | $log = function($something) { |
||
669 | var_dump($something); |
||
0 ignored issues
–
show
Security
Debugging Code
introduced
by
![]() |
|||
670 | return $something; |
||
671 | }; |
||
672 | return apply(curry($log), func_get_args()); |
||
673 | } |
||
674 | |||
675 | // Run the build |
||
676 | build_main(get_modules()); |
||
677 |