Skip to content

Commit fc5dac0

Browse files
author
Kevin Ballard
committed
Add a set of forEach accessors for working with arrays
1 parent 5620315 commit fc5dac0

5 files changed

Lines changed: 423 additions & 200 deletions

File tree

PMJSON.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
9E87937C1BC8341500BC6A15 /* ObjectiveC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E87937B1BC8341500BC6A15 /* ObjectiveC.swift */; };
2323
9E87937E1BC835F500BC6A15 /* Accessors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E87937D1BC835F500BC6A15 /* Accessors.swift */; };
2424
9EC4CD961DB83DE8003A4268 /* JSONParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EC4CD951DB83DE8003A4268 /* JSONParserTests.swift */; };
25+
9EC52A6A1DCBC2E900658723 /* JSONAccessorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EC52A691DCBC2E800658723 /* JSONAccessorTests.swift */; };
2526
9ECD04F51DC15C9800DBE7CA /* JSONTestSuite in Resources */ = {isa = PBXBuildFile; fileRef = 9ECD04F41DC15C9800DBE7CA /* JSONTestSuite */; };
2627
9ECD04F71DC15CAD00DBE7CA /* JSONTestSuite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9ECD04F61DC15CAD00DBE7CA /* JSONTestSuite.swift */; };
2728
/* End PBXBuildFile section */
@@ -59,6 +60,7 @@
5960
9E87937B1BC8341500BC6A15 /* ObjectiveC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectiveC.swift; sourceTree = "<group>"; };
6061
9E87937D1BC835F500BC6A15 /* Accessors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Accessors.swift; sourceTree = "<group>"; };
6162
9EC4CD951DB83DE8003A4268 /* JSONParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONParserTests.swift; sourceTree = "<group>"; };
63+
9EC52A691DCBC2E800658723 /* JSONAccessorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONAccessorTests.swift; sourceTree = "<group>"; };
6264
9ECD04F41DC15C9800DBE7CA /* JSONTestSuite */ = {isa = PBXFileReference; lastKnownFileType = folder; path = JSONTestSuite; sourceTree = "<group>"; };
6365
9ECD04F61DC15CAD00DBE7CA /* JSONTestSuite.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONTestSuite.swift; sourceTree = "<group>"; };
6466
/* End PBXFileReference section */
@@ -126,6 +128,7 @@
126128
isa = PBXGroup;
127129
children = (
128130
9E1B244F1BC73D7600E5BC19 /* JSONDecoderTests.swift */,
131+
9EC52A691DCBC2E800658723 /* JSONAccessorTests.swift */,
129132
9EC4CD951DB83DE8003A4268 /* JSONParserTests.swift */,
130133
9E4997EF1DC96E110049EECD /* JSONEncoderTests.swift */,
131134
9ECD04F61DC15CAD00DBE7CA /* JSONTestSuite.swift */,
@@ -269,6 +272,7 @@
269272
9EC4CD961DB83DE8003A4268 /* JSONParserTests.swift in Sources */,
270273
9ECD04F71DC15CAD00DBE7CA /* JSONTestSuite.swift in Sources */,
271274
9E4997F01DC96E110049EECD /* JSONEncoderTests.swift in Sources */,
275+
9EC52A6A1DCBC2E900658723 /* JSONAccessorTests.swift in Sources */,
272276
9E1B24501BC73D7600E5BC19 /* JSONDecoderTests.swift in Sources */,
273277
);
274278
runOnlyForDeploymentPostprocessing = 0;

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ Unless you explicitly state otherwise, any contribution intentionally submitted
251251
#### Development
252252

253253
* Add full support for decimal numbers (on supported platforms). This takes the form of a new `JSON` variant `.decimal`, any relevant accessors, and full parsing/decoding support with the new option `.useDecimalNumbers`. With this option, any number that would have been decoded as a `Double` will be decoded as an `NSDecimalNumber` instead.
254+
* Add a set of `forEach` accessors for working with arrays, similar to the existing `map` and `flatMap` accessors.
254255

255256
#### v1.2.1 (2016-10-27)
256257

Sources/JSONError.swift

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,6 +1330,21 @@ public extension JSON {
13301330
return try scoped(i, { try transform(elt) })
13311331
})
13321332
}
1333+
1334+
/// Calls `body` on each element of `array` in order.
1335+
///
1336+
/// If `body` throws a `JSONError`, the error will be modified to include the index
1337+
/// of the element that caused the error.
1338+
///
1339+
/// - Parameter array: The `JSONArray` to map over.
1340+
/// - Parameter body: A block that is called once for each element of `array`, along with the element's index.
1341+
/// - Throws: Rethrows any error thrown by `body`.
1342+
/// - Complexity: O(*N*).
1343+
static func forEach(_ array: JSONArray, _ body: (_ element: JSON, _ index: Int) throws -> Void) rethrows {
1344+
for (i, elt) in array.enumerated() {
1345+
try scoped(i, { try body(elt, i) })
1346+
}
1347+
}
13331348
}
13341349

13351350
public extension JSON {
@@ -1530,6 +1545,74 @@ public extension JSON {
15301545
func flatMapArrayOrNil<S: Sequence>(_ index: Int, _ transform: (JSON) throws -> S) throws -> [S.Iterator.Element]? {
15311546
return try getArrayOrNil(index, { try JSON.flatMap($0, transform) })
15321547
}
1548+
1549+
/// Subscripts the receiver with `key`, converts the value to an array, and calls `body` on
1550+
/// each element of the array in order.
1551+
///
1552+
/// - Note: This method is equivalent to `getArray(key, { try JSON.forEach($0, body) })`.
1553+
///
1554+
/// - Parameter key: The key to subscript the receiver with.
1555+
/// - Parameter body: A block that is called once for each element of the resulting array,
1556+
/// along with the element's index.
1557+
/// - Throws: `JSONError` if the receiver is not an object, `key` does not exist, or the value
1558+
/// is not an array. Also rethrows any error thrown by `transform`.
1559+
/// - Complexity: O(*N*).
1560+
func forEachArray(_ key: String, _ body: (_ element: JSON, _ index: Int) throws -> Void) throws {
1561+
try getArray(key, { try JSON.forEach($0, body) })
1562+
}
1563+
1564+
/// Subscripts the receiver with `index`, converts the value to an array, and calls `body` on
1565+
/// each element of the array in order.
1566+
///
1567+
/// - Note: This method is equivalent to `getArray(index, { try JSON.forEach($0, body) })`.
1568+
///
1569+
/// - Parameter key: The key to subscript the receiver with.
1570+
/// - Parameter body: A block that is called once for each element of the resulting array,
1571+
/// along with the element's index.
1572+
/// - Throws: `JSONError` if the receiver is not an array, `index` is out of bounds, or the
1573+
/// value is not an array. Also rethrows any error thrown by `body`.
1574+
/// - Complexity: O(*N*).
1575+
func forEachArray(_ index: Int, _ body: (_ element: JSON, _ index: Int) throws -> Void) throws {
1576+
try getArray(index, { try JSON.forEach($0, body) })
1577+
}
1578+
1579+
/// Subscripts the receiver with `key`, converts the value to an array, and calls `body` on
1580+
/// each element of the array in order.
1581+
///
1582+
/// Returns `false` if the `key` doesn't exist or the value is `null`.
1583+
///
1584+
/// - Note: This method is equivalent to `getArrayOrNil(key, { try JSON.forEach($0, body) }) != nil`.
1585+
///
1586+
/// - Parameter key: The key to subscript the receiver with.
1587+
/// - Parameter body: A block that is called once for each element of the resulting array,
1588+
/// along with the element's index.
1589+
/// - Returns: `true` if the `key` exists and the value was an array, or `false` if the key
1590+
/// doesn't exist or the value is `null`.
1591+
/// - Throws: `JSONError` if the receiver is not an object or the value is not an array or
1592+
/// `null`. Also rethrows any error thrown by `body`.
1593+
/// - Complexity: O(*N*).
1594+
@discardableResult
1595+
func forEachArrayOrNil(_ key: String, _ body: (_ element: JSON, _ index: Int) throws -> Void) throws -> Bool {
1596+
return try getArrayOrNil(key, { try JSON.forEach($0, body) }) != nil
1597+
}
1598+
1599+
/// Subscripts the receiver with `index`, converts the value to an array, and calls `body` on
1600+
/// each element of the array in order.
1601+
///
1602+
/// - Note: This method is equivalent to `getArrayOrNil(index, { try JSON.forEach($0, body) }) != nil`.
1603+
///
1604+
/// - Parameter index: The index to subscript the receiver with.
1605+
/// - Parameter body: A block that is called once for each element of the resulting array,
1606+
/// along with the element's index.
1607+
/// - Returns: `true` if the `key` exists and the value was an array, or `false` if the key
1608+
/// doesn't exist or the value is `null`.
1609+
/// - Throws: `JSONError` if the receiver is not an array or the value is not an array or
1610+
/// `null`. Also rethrows any error thrown by `body`.
1611+
/// - Complexity: O(*N*).
1612+
@discardableResult
1613+
func forEachArrayOrNil(_ index: Int, _ body: (_ element: JSON, _ index: Int) throws -> Void) throws -> Bool {
1614+
return try getArrayOrNil(index, { try JSON.forEach($0, body) }) != nil
1615+
}
15331616
}
15341617

15351618
public extension JSONObject {
@@ -1631,6 +1714,41 @@ public extension JSONObject {
16311714
func flatMapArrayOrNil<S: Sequence>(_ key: String, _ transform: (JSON) throws -> S) throws -> [S.Iterator.Element]? {
16321715
return try getArrayOrNil(key, { try JSON.flatMap($0, transform) })
16331716
}
1717+
1718+
/// Subscripts the receiver with `key`, converts the value to an array, and calls `body` on
1719+
/// each element of the array in order.
1720+
///
1721+
/// - Note: This method is equivalent to `getArray(key, { try JSON.forEach($0, body) })`.
1722+
///
1723+
/// - Parameter key: The key to subscript the receiver with.
1724+
/// - Parameter body: A block that is called once for each element of the resulting array,
1725+
/// along with the element's index.
1726+
/// - Throws: `JSONError` if the receiver is not an object, `key` does not exist, or the value
1727+
/// is not an array. Also rethrows any error thrown by `transform`.
1728+
/// - Complexity: O(*N*).
1729+
func forEachArray(_ key: String, _ body: (_ element: JSON, _ index: Int) throws -> Void) throws {
1730+
try getArray(key, { try JSON.forEach($0, body) })
1731+
}
1732+
1733+
/// Subscripts the receiver with `key`, converts the value to an array, and calls `body` on
1734+
/// each element of the array in order.
1735+
///
1736+
/// Returns `false` if the `key` doesn't exist or the value is `null`.
1737+
///
1738+
/// - Note: This method is equivalent to `getArrayOrNil(key, { try JSON.forEach($0, body) }) != nil`.
1739+
///
1740+
/// - Parameter key: The key to subscript the receiver with.
1741+
/// - Parameter body: A block that is called once for each element of the resulting array,
1742+
/// along with the element's index.
1743+
/// - Returns: `true` if the `key` exists and the value was an array, or `false` if the key
1744+
/// doesn't exist or the value is `null`.
1745+
/// - Throws: `JSONError` if the receiver is not an object or the value is not an array or
1746+
/// `null`. Also rethrows any error thrown by `body`.
1747+
/// - Complexity: O(*N*).
1748+
@discardableResult
1749+
func forEachArrayOrNil(_ key: String, _ body: (_ element: JSON, _ index: Int) throws -> Void) throws -> Bool {
1750+
return try getArrayOrNil(key, { try JSON.forEach($0, body) }) != nil
1751+
}
16341752
}
16351753

16361754
// MARK: -

0 commit comments

Comments
 (0)