Skip to content

Fix various spelling mistakes #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ A library for decoding and encoding json, built on top of @pointfreeco's [Parsin

## Introduction

As mentioned above, this library is built using the [Parsing](https://github.com/pointfreeco/swift-parsing) library, which is a library that provides a consistent story for writing _parsing_ code in Swift, that is, code that turns some _unstructured data_ into more _structured data_. You do that by constructing _parsers_ that are generic over both the (unstructured) _input_ and the (structued) _output_. What's really great is the fact the these parsers can be made _invertible_ (or bidirectional), meaning thay can also turn structured data _back_ into unstructed data, referred to as _printing_.
As mentioned above, this library is built using the [Parsing](https://github.com/pointfreeco/swift-parsing) library, which is a library that provides a consistent story for writing _parsing_ code in Swift, that is, code that turns some _unstructured data_ into more _structured data_. You do that by constructing _parsers_ that are generic over both the (unstructured) _input_ and the (structued) _output_. What's really great is the fact the these parsers can be made _invertible_ (or bidirectional), meaning they can also turn structured data _back_ into unstructured data, referred to as _printing_.

The *JSONParsing* library provides predefined parsers tuned specifically for when the _input is json_, giving you a convenient way of writing parsers capable of parsing (decoding) and printing (encoding) json. This style of dealing with json has a number of benefits compared to the *Codable* abstraction. More about that in the [Motivation](#motivation---why-not-use-codable) section.

Expand Down Expand Up @@ -145,7 +145,7 @@ Or perhaps:
"205,99,138"
```

The truth is, both representations are reasonable (as well as many other possibilities), and it's possible that you might have one API endpoint returning RGB colors in the first format, and another in the second format. But when using Codable, you would have to choose one of the formats to be the one used for the `RGBColor` type. To handle both variants, you would have to define two separate types, something like `RGBColorWithObjectRepresentaion` and `RGBColorWithStringRepresentation`, and conform both of them to `Codable`, with the different decoding/encoding strategies.
The truth is, both representations are reasonable (as well as many other possibilities), and it's possible that you might have one API endpoint returning RGB colors in the first format, and another in the second format. But when using Codable, you would have to choose one of the formats to be the one used for the `RGBColor` type. To handle both variants, you would have to define two separate types, something like `RGBColorWithObjectRepresentation` and `RGBColorWithStringRepresentation`, and conform both of them to `Codable`, with the different decoding/encoding strategies.

Using the *JSONParsing* library, you can easily just create two separate parsers, one for each alternative:

Expand Down Expand Up @@ -284,15 +284,15 @@ print(String(data: encodedJson, encoding: .utf8)!)

### Decoding and encoding logic out of sync

Codable has the really cool feature of being able to automatically sythesize the decoding and encoding implementations for Swift types, thanks to integration with the Swift compiler. Unfortunately, in practice, the automatically synthesized implementations will often not be correct for your usecase, because it assumes that your json data and your Swift data types _exactly_ match each other in structure. This will often not be the case, for various reasons. First, you might be dealing with JSON APIs that you don't own yourself and therefore might deliver data in a format that isn't ideal to your usecase. But even if you do own the API code, it might be used by multiple platforms, which means you can't tailor it specifically to work perfectly with your Swift code. Also, Swift has some features, such as enums, that simply _can't_ be expressed equivalently in json.
Codable has the really cool feature of being able to automatically synthesize the decoding and encoding implementations for Swift types, thanks to integration with the Swift compiler. Unfortunately, in practice, the automatically synthesized implementations will often not be correct for your use case, because it assumes that your json data and your Swift data types _exactly_ match each other in structure. This will often not be the case, for various reasons. First, you might be dealing with JSON APIs that you don't own yourself and therefore might deliver data in a format that isn't ideal to your use case. But even if you do own the API code, it might be used by multiple platforms, which means you can't tailor it specifically to work perfectly with your Swift code. Also, Swift has some features, such as enums, that simply _can't_ be expressed equivalently in json.

So in practice, when using Codable, you will often have to implement the decoding and encoding logic manually. And the problem in that situation, is that they have to be implemented _separately_. This means that, whenever the expected json format changes in any way, you have to remember to update both the `init(from:)` (decoding) and the `encode(to:)` (encoding) implementations accordingly.

With *JSONParsing* on the other hand, you can write a single json parser that can take care of both the decoding and the encoding (as was shown in the [Quick start](#quick-start) section). What this means is that you are guaranteed to always have the two transformations kept in sync as your json API evolves.

### Custom String parsing

Recall how we previously defined a json parser for the `RGBColor` type, where the json representation was a comma seperated string. It looked like this:
Recall how we previously defined a json parser for the `RGBColor` type, where the json representation was a comma separated string. It looked like this:

```swift
extension RGBColor {
Expand Down Expand Up @@ -539,7 +539,7 @@ public enum JSONValue: Equatable {

So when we call the `decode(_:)` and `encode(_:)` methods on the parsers, the decoding and encoding happens in two steps: the json data is transformed to/from the `JSONValue` type, and the `JSONValue` type is in turn transformed to/from the result type using the `Parser.parse`/`ParserPrinter.print` methods.

The primary usecase for the `JSONValue` type is just to act as this middle layer, to simplify the implementations of the various json parsers that ship with the library. However, it can actually be useful on its own. For instance, you might have code like this today:
The primary use case for the `JSONValue` type is just to act as this middle layer, to simplify the implementations of the various json parsers that ship with the library. However, it can actually be useful on its own. For instance, you might have code like this today:

```swift
let json: [String: Any] = [
Expand Down Expand Up @@ -591,7 +591,7 @@ let json: [String: Any] = [

This library ships with a number of json parsers, that can be composed together to deal with more complex json structures. As mentioned in the previous section, they all take values of the custom type `JSONValue` as input, so when using the `parse`/`print` methods, they convert to/from that type.

When you want to use them to decode/encode json _data_ (which is likely to be the most common usecase) you just use the `decode`/`encode` methods defined on them instead, which does the converting to from data for you.
When you want to use them to decode/encode json _data_ (which is likely to be the most common use case) you just use the `decode`/`encode` methods defined on them instead, which does the converting to from data for you.

### Null

Expand Down Expand Up @@ -1061,7 +1061,7 @@ try Person.jsonParser.print(person2)
// .object(["first_name": "Mark", "last_name": "Markson", "age": 20])
```

Instead of treating an abscent value as `nil`, you can optionally provide a `default` value, to use as a fallback:
Instead of treating an absent value as `nil`, you can optionally provide a `default` value, to use as a fallback:

```diff
struct Person {
Expand Down Expand Up @@ -1141,7 +1141,7 @@ extension Person {

### Integrating *JSONParsing* into *Codable* code

So that's one part of the equation, when it comes to integration with Codable. But what about the other way around? What if we actually _do_ have a json parser capable of decoding `Movie`s, and we're using Codable for the `Person` type instead. For that usecase, the library comes with overloads of the various methods on the decoding/encoding containers, that take a json parser as input. Let's see what it looks like to use this, by conforming the `Person` type to both the `Decodable` and the `Encodable` protocol:
So that's one part of the equation, when it comes to integration with Codable. But what about the other way around? What if we actually _do_ have a json parser capable of decoding `Movie`s, and we're using Codable for the `Person` type instead. For that use case, the library comes with overloads of the various methods on the decoding/encoding containers, that take a json parser as input. Let's see what it looks like to use this, by conforming the `Person` type to both the `Decodable` and the `Encodable` protocol:

```swift
extension Person: Decodable {
Expand Down
4 changes: 2 additions & 2 deletions Sources/JSONParsing/JSONParsers/Field.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation
import Parsing

/// A parser that tries to parse off a single field from a json object. The parser, if succesful, will remove the field from the input json,
/// A parser that tries to parse off a single field from a json object. The parser, if successful, will remove the field from the input json,
/// so that it can then be further parsed by other parsers.
///
/// For example, here's how to work with a json value that encodes a person. First, let's see how a single `Field` parser
Expand Down Expand Up @@ -84,7 +84,7 @@ public struct Field<Value: Parser>: Parser where Value.Input == JSONValue {
/// The parser to apply to the value of the field.
public let valueParser: Value

/// Initializes a parser that tries to parse off a single field from a json object. The parser, if succesful, will remove the field from
/// Initializes a parser that tries to parse off a single field from a json object. The parser, if successful, will remove the field from
/// the input json, so that it can then be further parsed by other parsers.
///
/// Here's how it can be used to parse the individual fields of a json representing a `Person`:
Expand Down
2 changes: 1 addition & 1 deletion Sources/JSONParsing/JSONParsers/JSONObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ where Key.Input == Substring, Key.Output: Hashable, Value.Input == JSONValue {
/// Initialize a parser that tries to parse a json value as an object, and turn it into a Swift `Dictionary` value.
///
/// You can provide an optional `range` to limit the number of key/value pair that are accepted,
/// as well as indvidual parsers to be used for the _keys_ and the _values_ respectively.
/// as well as individual parsers to be used for the _keys_ and the _values_ respectively.
///
/// For example, image that you want to parse a json that looks something like this:
///
Expand Down
2 changes: 1 addition & 1 deletion Sources/JSONParsing/JSONParsers/OptionalField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Parsing
/// A parser that, like the ``Field`` parser, tries to parse off a single field from a json object.
/// But unlike the `Field` parser, it allows for the field to _not exists_, in which case it just
/// returns `nil` or a `default` value if one is provided. Just like the `Field` parser it will,
/// if succesful, remove the field (if existent) from the input json.
/// if successful, remove the field (if existent) from the input json.
///
/// **Note: the `OptionalField` parser treats a field with an explicit `null` value as non-existent.**
///
Expand Down
2 changes: 1 addition & 1 deletion Tests/JSONParsingTests/JSONValue/PrettyPrintingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ final class PrettyPrintingTests: XCTestCase {
XCTAssertEqual(json.prettyPrinted(maxDepth: 0), "{ \"a\": true }")
}

func testMaxSubvalueCount0() {
func testMaxSubValueCount0() {
let json = JSONValue.object([
"key1": .boolean(true),
"key2": .string("hello"),
Expand Down