<commit_before>//
//  Extractor.swift
//  Himotoki
//
//  Created by <NAME> on 5/2/15.
//  Copyright (c) 2015 <NAME>. All rights reserved.
//

import Foundation

public struct Extractor {
    public let rawValue: AnyObject
    private let isDictionary: Bool

    internal init(_ rawValue: AnyObject) {
        self.rawValue = rawValue
        self.isDictionary = rawValue is NSDictionary
    }

    private func rawValue(keyPath: KeyPath) throws -> AnyObject? {
        if !isDictionary {
            throw DecodeError.TypeMismatch(
                expected: "Dictionary",
                actual: "\(rawValue)",
                keyPath: keyPath
            )
        }

        let components = ArraySlice(keyPath.components)
        return valueFor(components, rawValue)
    }

    /// - Throws: DecodeError
    public func value<T: Decodable where T.DecodedType == T>(keyPath: KeyPath) throws -> T {
        do {
            if let value: T = try rawValue(keyPath).map(decode) {
                return value
            } else {
                throw DecodeError.MissingKeyPath(keyPath)
            }
        } catch let DecodeError.TypeMismatch(expected, actual, _) {
            throw DecodeError.TypeMismatch(expected: expected, actual: actual, keyPath: keyPath)
        }
    }

    /// - Throws: DecodeError
    public func valueOptional<T: Decodable where T.DecodedType == T>(keyPath: KeyPath) throws -> T? {
        do {
            return try value(keyPath) as T
        } catch DecodeError.MissingKeyPath {
            return nil
        }
    }

    /// - Throws: DecodeError
    public func array<T: Decodable where T.DecodedType == T>(keyPath: KeyPath) throws -> [T] {
        guard let array: [T] = try arrayOptional(keyPath) else {
            throw DecodeError.MissingKeyPath(keyPath)
        }

        return array
    }

    /// - Throws: DecodeError
    public func arrayOptional<T: Decodable where T.DecodedType == T>(keyPath: KeyPath) throws -> [T]? {
        return try rawValue(keyPath).map(decodeArray)<commit_msg>Fix propagation of `DecodeError.MissingKeyPath` from `decode(e: Extractor)`<commit_after>//
//  Extractor.swift
//  Himotoki
//
//  Created by <NAME> on 5/2/15.
//  Copyright (c) 2015 <NAME>. All rights reserved.
//

import Foundation

public struct Extractor {
    public let rawValue: AnyObject
    private let isDictionary: Bool

    internal init(_ rawValue: AnyObject) {
        self.rawValue = rawValue
        self.isDictionary = rawValue is NSDictionary
    }

    private func rawValue(keyPath: KeyPath) throws -> AnyObject? {
        if !isDictionary {
            throw DecodeError.TypeMismatch(
                expected: "Dictionary",
                actual: "\(rawValue)",
                keyPath: keyPath
            )
        }

        let components = ArraySlice(keyPath.components)
        return valueFor(components, rawValue)
    }

    /// - Throws: DecodeError
    public func value<T: Decodable where T.DecodedType == T>(keyPath: KeyPath) throws -> T {
        guard let rawValue = try rawValue(keyPath) else {
            throw DecodeError.MissingKeyPath(keyPath)
        }

        do {
            return try decode(rawValue)
        } catch DecodeError.MissingKeyPath {
            throw DecodeError.MissingKeyPath(keyPath)
        } catch let DecodeError.TypeMismatch(expected, actual, _) {
            throw DecodeError.TypeMismatch(expected: expected, actual: actual, keyPath: keyPath)
        }
    }

    /// - Throws: DecodeError
    public func valueOptional<T: Decodable where T.DecodedType == T>(keyPath: KeyPath) throws -> T? {
        do {
            return try value(keyPath) as T
        } catch DecodeError.MissingKeyPath {
            return nil
        }
    }

    /// - Throws: DecodeError
    public func array<T: Decodable where T.DecodedType == T>(keyPath: KeyPath) throws -> [T] {
        guard let array: [T] = try arrayOptional(keyPath) else {
            throw DecodeError.MissingKeyPath(keyPath)
        }

        return array
    }

    /// - Throws: DecodeError
    public func arrayOptional<T: Decodable where T.DecodedType == T>(keyPath: KeyPath) throws -> [T]? {
        return try rawValue(keyPath).map(decodeArray)
{'fraction_non_alphanumeric': 0.09962049335863378, 'fraction_numerical': 0.003795066413662239, 'mean_word_length': 2.1470149253731345, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1324698', 'n_tokens_mistral': 1252, 'n_tokens_neox': 1205, 'n_words': 319}