jpsim / Yams

A Sweet and Swifty YAML parser.
https://jpsim.com/Yams
MIT License
1.11k stars 144 forks source link

Yams.serialize converts string in ' to number #174

Open sbarow opened 5 years ago

sbarow commented 5 years ago

Following on #116 when trying to serialise something likevalue: '10.0' the output will be value: 10.0.

Unfortunately doing value: !!str '10.0' still results in the output being number, tested with " and the same happens.

Example updating:

let updatedNode = try node.represented()
let serialized = try Yams.serialize(node: updatedNode)
try path.write(serialized)
sbarow commented 5 years ago

Doesn't look like this is specific to Yams but rather CYaml

Emitter.swift

    private func serializeScalar(_ scalar: Node.Scalar) throws {
    ...
        let scalar_style = yaml_scalar_style_t(rawValue: scalar.style.rawValue) // Returns `any` as that's what's passed in.
    ...
    }

Looking at this, a possible solution could be in Representer.swift with something like this:

private func canBecomeNumber(_ value: String) -> Bool {
    return Double(value) != nil
}

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

If you're okay with this I can put up a PR.

norio-nomura commented 5 years ago

Thank you for filing an issue!

Could you provide test code to reproduce the issue? The code I tried is as follows:

    func testSrializeNumberInSingleQuote() throws {
        let yaml = """
            value1: '10.0'
            value2: !!str '10.0'

            """
        let node = try Yams.compose(yaml: yaml)
        let updatedNode = try node.represented()
        let serialized = try Yams.serialize(node: updatedNode)
        print(serialized)
    }

result:


Test Suite 'Selected tests' started at 2019-02-16 09:23:46.575
Test Suite 'YamsTests.xctest' started at 2019-02-16 09:23:46.576
Test Suite 'EmitterTests' started at 2019-02-16 09:23:46.578
Test Case '-[YamsTests.EmitterTests testSrializeNumberInSingleQuote]' started.
value1: '10.0'
value2: '10.0'

Test Case '-[YamsTests.EmitterTests testSrializeNumberInSingleQuote]' passed (0.135 seconds).
Test Suite 'EmitterTests' passed at 2019-02-16 09:23:46.714.
     Executed 1 test, with 0 failures (0 unexpected) in 0.135 (0.136) seconds
Test Suite 'YamsTests.xctest' passed at 2019-02-16 09:23:46.715.
     Executed 1 test, with 0 failures (0 unexpected) in 0.135 (0.139) seconds
Test Suite 'Selected tests' passed at 2019-02-16 09:23:46.716.
     Executed 1 test, with 0 failures (0 unexpected) in 0.135 (0.140) seconds
Program ended with exit code: 0```