diff --git a/src/Json/Decode.elm b/src/Json/Decode.elm index db19881..5d004b9 100644 --- a/src/Json/Decode.elm +++ b/src/Json/Decode.elm @@ -1,5 +1,5 @@ module Json.Decode exposing - ( Decoder, string, bool, int, float + ( Decoder, string, stringAs, bool, int, float , nullable, list, array, dict, keyValuePairs, oneOrMore , field, at, index , maybe, oneOf @@ -23,7 +23,7 @@ JSON decoders][guide] to get a feel for how this library works! @docs field, at, index # Inconsistent Structure -@docs maybe, oneOf +@docs maybe, oneOf, stringAs # Run Decoders @docs decodeString, decodeValue, Value, Error, errorToString @@ -75,6 +75,53 @@ string = Elm.Kernel.Json.decodeString +{-| Decode the contents a JSON string with another decoder. This can be useful +if the JSON contains values that are really numbers, but exists as strings. For +example, say you want to decode the list stringified numbers. + + sneakyFloat : Decoder Float + sneakyFloat = + stringAs float + + -- decodeString (list sneakyFloat) "[\"1.5\", \"42.0\"]" == Ok [1.5, 42.0] + +Unfortunately, there could be times like this when you have to work with JSON +that uses strings to represent floats instead of just regular JSON numbers. If +you will need to do actual arithmetic on them, like multiplying them together, +then this functions allows you to parse them correctly with ease. + +It can be used together with `oneOf` to handle cases when a number is sometimes +represented by a JSON string and sometimes an actual JSON number. + +NOTE: When the these values are integers as strings, then there is a valid +reason NOT to decode them into integers. JavaScript uses floating point types +to represent integers as well, so there is no guarantee that it will be exact. +For example for unique IDs, it is better to use strings in JavaScript. +-} +stringAs : Decoder value -> Decoder value +stringAs decoder = + string + |> andThen + (\str -> + case decodeString decoder str of + Err err -> + failWithError err + + Ok val -> + succeed val + ) + + +{-| TODO: write a proper version of this function. +Depends on [#25][issue-25] + +[issue-25]: https://github.com/elm/json/issues/25 +-} +failWithError : Error -> Decoder a +failWithError = + fail << errorToString + + {-| Decode a JSON boolean into an Elm `Bool`. decodeString bool "true" == Ok True diff --git a/tests/Json.elm b/tests/Json.elm index 614a1dd..9b35eb1 100644 --- a/tests/Json.elm +++ b/tests/Json.elm @@ -12,6 +12,7 @@ tests : Test tests = describe "Json decode" [ intTests + , stringAsTests , customTests ] @@ -54,6 +55,30 @@ intTests = ] +stringAsTests : Test +stringAsTests = + let + testStringAs decoder val str = + case Json.decodeString (Json.stringAs decoder) str of + Ok _ -> + Expect.equal val True + + Err _ -> + Expect.equal val False + int = Json.int + float = Json.float + in + describe "Jsong decode stringAs" + [ test "int string -> int" <| testStringAs int True "\"3\"" + , test "float string -> int" <| testStringAs int False "\"3.0\"" + , test "int -> int" <| testStringAs int False "3" + , test "float -> int" <| testStringAs int False "3.0" + , test "int string -> float" <| testStringAs float False "\"3\"" + , test "float string -> float" <| testStringAs float True "\"3.0\"" + , test "int -> float" <| testStringAs float False "3" + , test "float -> float" <| testStringAs float False "3.0" + ] + customTests : Test customTests = let