<commit_before>//
//  Representer.swift
//  Yams
//
//  Created by <NAME> on 1/8/17.
//  Copyright (c) 2017 Yams. All rights reserved.
//

#if SWIFT_PACKAGE
import CYaml
#endif
#if os(Linux)
import CoreFoundation
#endif
import Foundation

public extension Node {
    /// Initialize a `Node` with a value of `NodeRepresentable`.
    ///
    /// - parameter representable: Value of `NodeRepresentable` to represent as a `Node`.
    ///
    /// - throws: `YamlError`.
    init<T: NodeRepresentable>(_ representable: T) throws {
        self = try representable.represented()
    }
}

// MARK: - NodeRepresentable
/// Type is representable as `Node`.
public protocol NodeRepresentable {
    /// This value's `Node` representation.
    func represented() throws -> Node
}

extension Node: NodeRepresentable {
    /// This value's `Node` representation.
    public func represented() throws -> Node {
        return self
    }
}

extension Array: NodeRepresentable {
    /// This value's `Node` representation.
    public func represented() throws -> Node {
        let nodes = try map(represent)
        return Node(nodes, Tag(.seq))
    }
}

extension Dictionary: NodeRepresentable {
    /// This value's `Node` representation.
    public func represented() throws -> Node {
        let pairs = try map { (key: try represent($0.0), value: try represent($0.1)) }
        return Node(pairs.sorted { $0.key < $1.key }, Tag(.map))
    }
}

private func represent(_ value: Any) throws -> Node {
    if let string = value as? String {
        return Node(string)
    } else if let representable = value as? NodeRepresentable {
        return try representable.represented()
    }
    throw YamlError.representer(problem: "Failed to represent \(value)")
}

// MARK: - ScalarRepresentable
/// Type is representable as `Node.scalar`.
public protocol ScalarRepresentable: NodeRepresentable {
    /// This value's `Node.scalar` representation.
    func represented() -> Node.Scalar
}

extension ScalarRepresentable {
    /// This value's `Node.scalar` representation.
    public func represented() throws -> Node {
        return .scalar(represented())
    }
}

extension Bool: ScalarRepresentable {
    /// This value's `Node.scalar` representation.
    public func represented() -> Node.Scalar {
        return .init(self ? "true" : "false", Tag(.bool))
    }
}

extension Data: ScalarRepresentable {
    /// This value's `Node.scalar` representation.
    public func represented() -> Node.Scalar {
        return .init(base64EncodedString(), Tag(.binary))
    }
}

extension Date: ScalarRepresentable {
    /// This value's `Node.scalar` representation.
    public func represented() -> Node.Scalar {
        return .init(iso8601String, Tag(.timestamp))
    }

    private var iso8601String: String {
        let (integral, millisecond) = timeIntervalSinceReferenceDate.separateFractionalSecond(with: 3)
        guard millisecond != 0 else { return iso8601Formatter.string(from: self) }

        let dateWithoutMillisecond = Date(timeIntervalSinceReferenceDate: integral)
        return iso8601WithoutZFormatter.string(from: dateWithoutMillisecond) +
            String(format: ".%03d", millisecond).trimmingCharacters(in: characterSetZero) + "Z"
    }

    private var iso8601StringWithFullNanosecond: String {
        let (integral, nanosecond) = timeIntervalSinceReferenceDate.separateFractionalSecond(with: 9)
        guard nanosecond != 0 else { return iso8601Formatter.string(from: self) }

        let dateWithoutNanosecond = Date(timeIntervalSinceReferenceDate: integral)
        return iso8601WithoutZFormatter.string(from: dateWithoutNanosecond) +
            String(format: ".%09d", nanosecond).trimmingCharacters(in: characterSetZero) + "Z"
    }
}

private extension TimeInterval {
    /// Separates into integral and fractional, then round fractional to precision digits Int
    /// - returns: Tuple of integral part and converted fractional part
    func separateFractionalSecond(with precision: Int) -> (integral: TimeInterval, fractional: Int) {
        var integral = 0.0
        let fractional = modf(self, &integral)
        let radix = pow(10.0, TimeInterval(precision))
        let rounded = Int((fractional * radix).rounded())
        let quotient = rounded / Int(radix)
        return quotient != 0 ? // carry-up?
            (integral + TimeInterval(quotient), rounded % Int(radix)) :
            (integral, rounded)
    }
}

private let characterSetZero = CharacterSet(charactersIn: "0")

private let iso8601Formatter: DateFormatter = {
    var formatter = DateFormatter()
    formatter.locale = Locale(identifier: "en_US_POSIX")
    formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"
    formatter.timeZone = TimeZone(secondsFromGMT: 0)
    return formatter
}()
<commit_msg>Fix `TimeInterval(precision)` wasn't a time interval<commit_after>//
//  Representer.swift
//  Yams
//
//  Created by <NAME> on 1/8/17.
//  Copyright (c) 2017 Yams. All rights reserved.
//

#if SWIFT_PACKAGE
import CYaml
#endif
#if os(Linux)
import CoreFoundation
#endif
import Foundation

public extension Node {
    /// Initialize a `Node` with a value of `NodeRepresentable`.
    ///
    /// - parameter representable: Value of `NodeRepresentable` to represent as a `Node`.
    ///
    /// - throws: `YamlError`.
    init<T: NodeRepresentable>(_ representable: T) throws {
        self = try representable.represented()
    }
}

// MARK: - NodeRepresentable
/// Type is representable as `Node`.
public protocol NodeRepresentable {
    /// This value's `Node` representation.
    func represented() throws -> Node
}

extension Node: NodeRepresentable {
    /// This value's `Node` representation.
    public func represented() throws -> Node {
        return self
    }
}

extension Array: NodeRepresentable {
    /// This value's `Node` representation.
    public func represented() throws -> Node {
        let nodes = try map(represent)
        return Node(nodes, Tag(.seq))
    }
}

extension Dictionary: NodeRepresentable {
    /// This value's `Node` representation.
    public func represented() throws -> Node {
        let pairs = try map { (key: try represent($0.0), value: try represent($0.1)) }
        return Node(pairs.sorted { $0.key < $1.key }, Tag(.map))
    }
}

private func represent(_ value: Any) throws -> Node {
    if let string = value as? String {
        return Node(string)
    } else if let representable = value as? NodeRepresentable {
        return try representable.represented()
    }
    throw YamlError.representer(problem: "Failed to represent \(value)")
}

// MARK: - ScalarRepresentable
/// Type is representable as `Node.scalar`.
public protocol ScalarRepresentable: NodeRepresentable {
    /// This value's `Node.scalar` representation.
    func represented() -> Node.Scalar
}

extension ScalarRepresentable {
    /// This value's `Node.scalar` representation.
    public func represented() throws -> Node {
        return .scalar(represented())
    }
}

extension Bool: ScalarRepresentable {
    /// This value's `Node.scalar` representation.
    public func represented() -> Node.Scalar {
        return .init(self ? "true" : "false", Tag(.bool))
    }
}

extension Data: ScalarRepresentable {
    /// This value's `Node.scalar` representation.
    public func represented() -> Node.Scalar {
        return .init(base64EncodedString(), Tag(.binary))
    }
}

extension Date: ScalarRepresentable {
    /// This value's `Node.scalar` representation.
    public func represented() -> Node.Scalar {
        return .init(iso8601String, Tag(.timestamp))
    }

    private var iso8601String: String {
        let (integral, millisecond) = timeIntervalSinceReferenceDate.separateFractionalSecond(with: 3)
        guard millisecond != 0 else { return iso8601Formatter.string(from: self) }

        let dateWithoutMillisecond = Date(timeIntervalSinceReferenceDate: integral)
        return iso8601WithoutZFormatter.string(from: dateWithoutMillisecond) +
            String(format: ".%03d", millisecond).trimmingCharacters(in: characterSetZero) + "Z"
    }

    private var iso8601StringWithFullNanosecond: String {
        let (integral, nanosecond) = timeIntervalSinceReferenceDate.separateFractionalSecond(with: 9)
        guard nanosecond != 0 else { return iso8601Formatter.string(from: self) }

        let dateWithoutNanosecond = Date(timeIntervalSinceReferenceDate: integral)
        return iso8601WithoutZFormatter.string(from: dateWithoutNanosecond) +
            String(format: ".%09d", nanosecond).trimmingCharacters(in: characterSetZero) + "Z"
    }
}

private extension TimeInterval {
    /// Separates into integral and fractional, then round fractional to precision digits Int
    /// - returns: Tuple of integral part and converted fractional part
    func separateFractionalSecond(with precision: Int) -> (integral: TimeInterval, fractional: Int) {
        var integral = 0.0
        let fractional = modf(self, &integral)
        let radix = pow(10.0, Double(precision))
        let rounded = Int((fractional * radix).rounded())
        let quotient = rounded / Int(radix)
        return quotient != 0 ? // carry-up?
            (integral + TimeInterval(quotient), rounded % Int(radix)) :
            (integral, rounded)
    }
}

private let characterSetZero = CharacterSet(charactersIn: "0")

private let iso8601Formatter: DateFormatter = {
    var formatter = DateFormatter()
    formatter.locale = Locale(identifier: "en_US_POSIX")
    formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"
    formatter.timeZone = TimeZone(secondsFromGMT: 0)
    return formatter
}()

{'fraction_non_alphanumeric': 0.11522077922077922, 'fraction_numerical': 0.0132987012987013, 'mean_word_length': 3.163494809688581, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 29, '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': '1659571', 'n_tokens_mistral': 2888, 'n_tokens_neox': 2637, 'n_words': 767}