public static function wrap($callable)
    {
        $parts          = explode('::', static::represent($callable));
        if (count($parts) == 1) {
            // We wrapped a function.
            $reflector = new \ReflectionFunction($callable);
        } else {
            if (!is_array($callable)) {
                // We wrapped a Closure or some invokable object.
                $callable = array($callable, $parts[1]);
            }
            $reflector = new \ReflectionMethod($callable[0], $callable[1]);
        }

        // References are lost, unless __invoke()'s signature also requires them.
        // We must also make sure default values are preserved.
        $args = array();
        foreach ($reflector->getParameters() as $argReflect) {
            $arg = '';
            if ($argReflect->isPassedByReference()) {
                $arg .= '&';
            }
            $arg .= '$a' . count($args);
            if ($argReflect->isOptional()) {
                $arg .= '=' . var_export($argReflect->getDefaultValue(), true);
            } else {
                $arg .= '=null';
            }
            $args[] = $arg;
        }

        $args   = implode(',', $args);
        $class  = 'Wrapped_' . sha1($args);
        if (!class_exists("\\Erebot\\CallableWrapper\\$class", false)) {
            $tpl = "
                namespace Erebot\\CallableWrapper {
                    class $class extends \\Erebot\\CallableWrapper
                    {
                        public function __invoke($args)
                        {
                            // HACK: we use debug_backtrace() to get (and pass along)
                            // references for call_user_func_array().

                            // Starting with PHP 5.4.0, it is possible to limit
                            // the number of stack frames returned.
                            if (version_compare(PHP_VERSION, '5.4', '>='))
                                \$bt = debug_backtrace(0, 1);
                            // Starting with PHP 5.3.6, the first argument
                            // to debug_backtrace() is a bitmask of options.
                            else if (version_compare(PHP_VERSION, '5.3.6', '>='))
                                \$bt = debug_backtrace(0);
                            else
                                \$bt = debug_backtrace(FALSE);

                            if (isset(\$bt[0]['args']))
                                \$args =& \$bt[0]['args'];
                            else
                                \$args = array();
                            return call_user_func_array(\$this->callable, \$args);
                        }
                    }
                }
            ";
            eval($tpl);
        }
        $class = "\\Erebot\\CallableWrapper\\$class";
        return new $class($callable);
    }