Completed
Push — master ( 7da718...9c5b3d )
by Matteo
7s
created

functions.php ➔ __()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 2
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 4
ccs 1
cts 1
cp 1
crap 1
rs 10
1
<?php
2
3
namespace Cypress\Curry;
4
5
use Cypress\Curry\Placeholder;
6
7
/**
8
 * @param callable $callable
9
 * @return callable
10
 */
11
function curry($callable)
12
{
13 9
    if (_number_of_required_params($callable) < 2)
14 9
        return _make_function($callable);
15 7
    return _curry_array_args($callable, _rest(func_get_args()));
16
}
17
18
/**
19
 * @param $callable
20
 * @param array $args pass the arguments to be curried as an array
21
 *
22
 * @return callable
23
 */
24
function curry_args($callable, array $args)
25
{
26 2
    return _curry_array_args($callable, $args);
27
}
28
29
/**
30
 * @param callable $callable
31
 * @return callable
32
 */
33
function curry_right($callable)
34
{
35 4
    if (_number_of_required_params($callable) < 2)
36 4
        return _make_function($callable);
37 4
    return _curry_array_args($callable, _rest(func_get_args()), false);
38
}
39
40
/**
41
 * @param callable $callable
42
 * @param array $args pass the arguments to be curried as an array
43
 *
44
 * @return callable
45
 */
46
function curry_right_args($callable, array $args)
47
{
48 3
    return _curry_array_args($callable, $args, false);
49
}
50
51
/**
52
 * @param callable $callable
53
 * @param $args
54
 * @param bool $left
55
 * @return callable
56
 */
57
function _curry_array_args($callable, $args, $left = true)
58
{
59
    return function () use ($callable, $args, $left) {
60 15
        if (_is_fullfilled($callable, $args)) {
61 4
            return _execute($callable, $args, $left);
62
        }
63 11
        $newArgs = array_merge($args, func_get_args());
64 11
        if (_is_fullfilled($callable, $newArgs)) {
65 11
            return _execute($callable, $newArgs, $left);
66
        }
67 6
        return _curry_array_args($callable, $newArgs, $left);
68 15
    };
69
}
70
71
/**
72
 * @internal
73
 * @param $callable
74
 * @param $args
75
 * @param $left
76
 * @return mixed
77
 */
78
function _execute($callable, $args, $left)
79
{
80 15
    if (! $left) {
81 7
        $args = array_reverse($args);
82 7
    }
83
84 15
    $placeholders = _placeholder_positions($args);
85 15
    if (0 < count($placeholders)) {
86 1
        $n = _number_of_required_params($callable);
87 1
        if ($n <= _last($placeholders[count($placeholders) - 1])) {
88
            // This means that we have more placeholders then needed
89
            // I know that throwing exceptions is not really the 
90
            // functional way, but this case should not happen.
91
            throw new \Exception("Argument Placeholder found on unexpected position !");
92
        }
93 1
        foreach ($placeholders as $i) {
94 1
            $args[$i] = $args[$n];
95 1
            array_splice($args, $n, 1);
96 1
        }
97 1
    }
98
99 15
    return call_user_func_array($callable, $args);
100
}
101
102
/**
103
 * @internal
104
 * @param array $args
105
 * @return array
106
 */
107
function _rest(array $args)
108
{
109 11
    return array_slice($args, 1);
110
}
111
112
/**
113
 * @internal
114
 * @param callable $callable
115
 * @param $args
116
 * @return bool
117
 */
118
function _is_fullfilled($callable, $args)
119
{
120
    $args = array_filter($args, function($arg) {
121 20
        return ! _is_placeholder($arg);
122 22
    });
123 22
    return count($args) >= _number_of_required_params($callable);
124
}
125
126
/**
127
 * @internal
128
 * @param $callable
129
 * @return int
130
 */
131
function _number_of_required_params($callable)
132
{
133 24
    if (is_array($callable)) {
134 16
        $refl = new \ReflectionClass($callable[0]);
135 16
        $method = $refl->getMethod($callable[1]);
136 16
        return $method->getNumberOfRequiredParameters();
137
    }
138 8
    $refl = new \ReflectionFunction($callable);
139 8
    return $refl->getNumberOfRequiredParameters();
140
}
141
142
/**
143
 * if the callback is an array(instance, method), 
144
 * it returns an equivalent function for PHP 5.3 compatibility.
145
 *
146
 * @internal 
147
 * @param  callable $callable
148
 * @return callable
149
 */
150
function _make_function($callable)
151
{
152 3
    if (is_array($callable))
153
        return function() use($callable) {
154 1
            return call_user_func_array($callable, func_get_args());
155 1
        };
156 2
    return $callable;
157
}
158
159
/**
160
 * Checks if an argument is a placeholder.
161
 *
162
 * @internal
163
 * @param  mixed  $arg
164
 * @return boolean
165
 */
166
function _is_placeholder($arg)
167
{
168 20
    return $arg instanceof Placeholder;
169
}
170
171
/**
172
 * Gets an array of placeholders positions in the given arguments.
173
 *
174
 * @internal
175
 * @param  array $args
176
 * @return array
177
 */
178
function _placeholder_positions($args)
179
{
180 15
    return array_keys(array_filter($args, 'Cypress\\Curry\\_is_placeholder'));
181
}
182
183
/**
184
 * Get the last element in an array.
185
 *
186
 * @internal
187
 * @param  array $array
188
 * @return mixed
189
 */
190
function _last($array)
191
{
192 1
    return $array[count($array) - 1];
193
}
194
195
/**
196
 * Gets a special placeholder value used to specify "gaps" within curried 
197
 * functions, allowing partial application of any combination of arguments, 
198
 * regardless of their positions. Should be used only for required arguments.
199
 * When used, optional arguments must be at the end of the arguments list.
200
 *
201
 * @return Cypress\Curry\Placeholder
202
 */
203
function __()
204
{
205 1
    return Placeholder::get();
206
}
207