public function scopify(NormalizableInterface $object, $scope)
    {
        $scopes = $object->getScopes();
        if (!isset($scopes[$scope])) {
            throw new ScopeNotFoundException(sprintf(
                'Invalid scope for %s object, only ["%s"] supported, "%s" given.',
                get_class($object),
                implode('", "', array_keys($scopes)),
                $scope
            ));
        }
        if (empty($scopes) || empty($scopes[$scope])) {
            return array();
        }

        $read = \Closure::bind(
            $this->createReadingDelegate(),
            $object,
            get_class($object)
        );

        // simple value scope
        if (is_string($scopes[$scope])) {
            return $read($scopes[$scope], $this->propertyAccessor);
        }

        // flatten fields
        $fields = array();
        $stack = array($scopes[$scope]);
        do {
            $stackedField = array_shift($stack);
            foreach ($stackedField as $fieldConfig) {
                if (strpos($fieldConfig, '@') === 0) {
                    if (!array_key_exists(
                        $inheritedScope = str_replace('@', '', $fieldConfig),
                        $scopes
                    )) {
                        throw new ScopeNotFoundException(sprintf(
                            'Invalid inherited scope for %s object at %s scope, only ["%s"] supported, "%s" given.',
                            get_class($object),
                            $scope,
                            implode(', ', array_keys($scopes)),
                            $inheritedScope
                        ));
                    }

                    array_unshift($stack, $scopes[$inheritedScope]);
                    continue;
                }

                $fields[] = $fieldConfig;
            }
        } while (!empty($stack));

        // begin normalization
        $data = array();
        foreach ($fields as $field) {
            // optionnal field detection
            $optionnal = false;
            if (strpos($field, '?') !== false) {
                $field = str_replace('?', '', $field);
                $optionnal = true;
            }

            // external scopes : first in, last in
            $subScope = 'default';
            if (strpos($field, '@') !== false) {
                list($field, $subScope) = explode('@', $field);
            }
            if (isset($data[$field])) {
                continue;
            }

            $value = $this->normalize(
                $read($field, $this->propertyAccessor),
                $subScope
            );

            // nullable ?
            if (!(is_null($value) && $optionnal)) {
                $data[$field] = $value;
            }
        }

        return $data;
    }