From cefa5015665083211e927d7a7f19ac821603a375 Mon Sep 17 00:00:00 2001 From: Daniel Thorpe Date: Fri, 6 Nov 2015 00:35:53 +0000 Subject: [PATCH 01/11] [development]: Removes doc % badge --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 66d0b20..fbb6f1d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ [![Build status](https://badge.buildkite.com/265eb9670a2ef6b73eebf37769a8455c402509f71f09c4f51e.svg)](https://buildkite.com/blindingskies/money?branch=development) [![codecov.io](https://codecov.io/github/danthorpe/Money/coverage.svg?branch=development&token=gI70muNOjA)](https://codecov.io/github/danthorpe/Money?branch=development) -[![Doc-Percent](https://img.shields.io/cocoapods/metrics/doc-percent/Money.svg)](http://cocoadocs.org/docsets/Money/1.0.0) [![Cocoapods Compatible](https://img.shields.io/cocoapods/v/Money.svg)](https://img.shields.io/cocoapods/v/Money.svg) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![Platform](https://img.shields.io/cocoapods/p/Money.svg?style=flat)](http://cocoadocs.org/docsets/Money) @@ -226,4 +225,4 @@ Money is available under the MIT license. See the LICENSE file for more info. ## Disclaimer -Usage of this framework prevents the author, Daniel Thorpe, from being held liable for any losses incurred by the user through their use of the framework. \ No newline at end of file +Usage of this framework prevents the author, Daniel Thorpe, from being held liable for any losses incurred by the user through their use of the framework. From 0517eb327ca7276821c2edd35de8921b5af0d055 Mon Sep 17 00:00:00 2001 From: Daniel Thorpe Date: Fri, 6 Nov 2015 12:35:20 +0000 Subject: [PATCH 02/11] [MNY-16]: Fixes up the names in the FX tests --- Tests/FXOpenExchangeRatesTests.swift | 9 +++------ Tests/FXYahooTests.swift | 5 ++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/Tests/FXOpenExchangeRatesTests.swift b/Tests/FXOpenExchangeRatesTests.swift index 7ba7be0..d284ee7 100644 --- a/Tests/FXOpenExchangeRatesTests.swift +++ b/Tests/FXOpenExchangeRatesTests.swift @@ -47,8 +47,6 @@ class FXFreeOpenExchangeRatesTests: FXProviderTests { typealias TestableProvider = TestableFXRemoteProvider typealias FaultyProvider = FaultyFXRemoteProvider - let usd: USD = 100 - func test__name() { XCTAssertEqual(Provider.name(), "OpenExchangeRates.org USDEUR") } @@ -104,7 +102,7 @@ class FXFreeOpenExchangeRatesTests: FXProviderTests { func test__faulty_provider() { let expectation = expectationWithDescription("Test: \(__FUNCTION__)") - FaultyProvider.fx(usd) { result in + FaultyProvider.fx(100) { result in guard let error = result.error else { XCTFail("Should have received a network error.") return @@ -121,11 +119,10 @@ class FXFreeOpenExchangeRatesTests: FXProviderTests { waitForExpectationsWithTimeout(1, handler: nil) } - func test__exhange_usd_to_eur() { - + func test__fx() { let expectation = expectationWithDescription("Test: \(__FUNCTION__)") - TestableProvider.fx(usd) { result in + TestableProvider.fx(100) { result in if let usd = result.value { XCTAssertEqual(usd, 92.09) } diff --git a/Tests/FXYahooTests.swift b/Tests/FXYahooTests.swift index c505e0d..6b6d6be 100644 --- a/Tests/FXYahooTests.swift +++ b/Tests/FXYahooTests.swift @@ -62,10 +62,9 @@ class FXYahooTests: FXProviderTests { } func test__faulty_provider() { - let gbp: GBP = 100 let expectation = expectationWithDescription("Test: \(__FUNCTION__)") - FaultyProvider.fx(gbp) { result in + FaultyProvider.fx(100) { result in guard let error = result.error else { XCTFail("Should have received a network error.") return @@ -82,7 +81,7 @@ class FXYahooTests: FXProviderTests { waitForExpectationsWithTimeout(1, handler: nil) } - func test__exhange_gbp_to_eur() { + func test__fx() { let expectation = expectationWithDescription("Test: \(__FUNCTION__)") TestableProvider.fx(100) { result in From ad78fff2969f291cf1b4cfd5988e10fac8ee0939 Mon Sep 17 00:00:00 2001 From: Daniel Thorpe Date: Fri, 6 Nov 2015 12:52:27 +0000 Subject: [PATCH 03/11] [MNY-16]: Fixes spelling mistakes in README --- README.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index fbb6f1d..4a33531 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Money is a Swift framework for iOS, watchOS, tvOS and OS X. It provides types an ## Usage -The Money framework defines the type, `Money` which represents money in the device’s current locale. The following code: +The Money framework defines the type `Money`, which represents money in the device’s current locale. The following code: ```swift let money: Money = 100 @@ -57,12 +57,12 @@ Because the currencies are typed, it means that they cannot be combined together ```swift let money = pounds + euros ``` -> // Binary operator '+' cannot be applied to operands of type 'GBP' (aka '_Money<Currency.GBP>') and 'EUR' (aka '_Money<Currency.EUR>') +> Binary operator '+' cannot be applied to operands of type 'GBP' (aka '_Money<Currency.GBP>') and 'EUR' (aka '_Money<Currency.EUR>') Of course, `Money` supports the usual suspects of decimal arithmetic operators, so you can add, subtract, multiply, divide values of the same type, and values with `Int` and `Double` with some limitations. ## Foreign Currency Exchange (FX) -To represent a foreign exchange transaction, i.e. converting `USD` to `EUR`, use a FX service provider. There is built in support for [Yahoo](https://finance.yahoo.com/currency-converter/#from=USD;to=EUR;amt=1) and [OpenExchangeRates.org](https://openexchangerates.org) services. But it’s possible for consumers to create their own. +To represent a foreign exchange transaction, i.e. converting `USD` to `EUR`, use a FX service provider. There is built in support for [Yahoo](https://finance.yahoo.com/currency-converter/#from=USD;to=EUR;amt=1) and [OpenExchangeRates.org](https://openexchangerates.org) services. But it’s possible for consumers to create their own too. The following code snippet represent a currency exchange using Yahoo’s currency converter. @@ -120,6 +120,10 @@ public static func quoteFromNetworkResult(result: Result<(NSData?, NSURLResponse Note that the provider doesn’t need to perform any networking itself. It is all done by the framework. This is a deliberate architectural design as it makes it much easier to unit test the adaptor code. +Additionally FX APIs will be added shortly, +1. To calculate the reverse exchange, i.e. how many dollars would I need to get so many euros. +2. For the two (forward & reverse) exchanges, I’ll also add a `quote` function, which will return the `FXQuote` object. This might be useful if your app needs to persist the quote used for an exchange. + # Creating custom currencies If your app has its own currency e.g. ⭐️s or 💎s or even 🐝s, you might want to consider making a type for it. @@ -162,15 +166,17 @@ print(“I have \(bees)”) And of course if you have an IAP for purchasing in-app currency, then I’m sure a custom FX provider would be handy. -Take a look at the example project, Custom Money, for a an example of a custom local FX provider to exchange your 🐝s. +Take a look at the example project, Custom Money, for an example of a custom local FX provider to exchange your 🐝s. ## Installation -Money builds as a cross platform (iOS, OS X, watchOS) extension compatible framework. It is also available via CocoaPods +Money builds as a cross platform (iOS, OS X, watchOS) extension compatible framework. It is compatible with [Carthage](https://github.com/carthage/carthage). It is also available via CocoaPods ```ruby pod ‘Money’ ``` +At of writing there seems to be issues with the CocoaDocs generator for pure Swift 2 projects. This means that the project doesn’t have a page/docs in CocoaPods sites. + ## Architectural style Swift is designed to have a focus on safety, enabled primarily through strong typing. This framework fully embraces this ethos and uses generics heavily to achieve this goal. @@ -182,7 +188,7 @@ Finally, we auto-generate the code which defines all the currencies and money ty Cocoa has two type which can perform decimal arithmetic, these are `NSDecimalNumber` and `NSDecimal`. `NSDecimal` is faster, but is trickier to work with, and doesn’t have support for limiting the scale of the numbers (which is pretty important when working with currencies). -`DecimalNumberType` is a protocol which refines refines `SignedNumberType` and defines some functions (`add`, `subtract` etc to support the arithmetic). It is also generic over two types, the underlying storage, and the behaviors. +`DecimalNumberType` is a protocol which refines `SignedNumberType` and defines its own functions, `add`, `subtract` etc to support the arithmetic. It is generic over two types, the underlying storage, and the behaviors. `DecimalNumberType.DecimalStorageType` exists so that conforming types can utilize either `NSDecimalNumber` or `NSDecimal` as their underling storage type. From 80e57dac4f4f3ac9fd65e7a39063c06495c2ea43 Mon Sep 17 00:00:00 2001 From: Daniel Thorpe Date: Fri, 6 Nov 2015 13:17:13 +0000 Subject: [PATCH 04/11] [MNY-16]: Makes FXQuote conform to NSCoding. --- Money/FX.swift | 11 ++++++++++- Tests/FXTests.swift | 24 ++++++++++++++++++------ Tests/MoneyTests.swift | 12 ++++++++++++ 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/Money/FX.swift b/Money/FX.swift index 4098bae..2c52501 100644 --- a/Money/FX.swift +++ b/Money/FX.swift @@ -26,6 +26,7 @@ import Foundation +import ValueCoding import Result import SwiftyJSON @@ -51,7 +52,7 @@ public protocol MoneyPairType { The minimum interface required to perform a foreign currency exchange. */ -public class FXQuote { +public class FXQuote: NSObject, NSCoding { /// The exchange rate, stored as a `BankersDecimal`. public let rate: BankersDecimal @@ -63,6 +64,14 @@ public class FXQuote { self.rate = rate } + public required init?(coder aDecoder: NSCoder) { + rate = BankersDecimal.decode(aDecoder.decodeObjectForKey("rate"))! + } + + public func encodeWithCoder(aCoder: NSCoder) { + aCoder.encodeObject(rate.encoded, forKey: "rate") + } + /** ## Calculate transaction value Lets assume we want to convert EUR 100 in to USD. The diff --git a/Tests/FXTests.swift b/Tests/FXTests.swift index 9244222..12ddfb1 100644 --- a/Tests/FXTests.swift +++ b/Tests/FXTests.swift @@ -109,12 +109,6 @@ class FXErrorTests: XCTestCase { class FXProviderTests: XCTestCase { - func createGarbageData() -> NSData { - let path = NSBundle(forClass: self.dynamicType).pathForResource("Troll", ofType: "png") - let data = NSData(contentsOfFile: path!) - return data! - } - func dvrJSONFromCassette(name: String) -> JSON? { guard let path = NSBundle(forClass: self.dynamicType).pathForResource(name, ofType: "json"), data = NSData(contentsOfFile: path) else { @@ -134,3 +128,21 @@ class FXLocalProviderTests: XCTestCase { XCTAssertEqual(usd, 11) } } + +class FXQuoteTests: XCTestCase { + + var quote: FXQuote! + + func archiveEncodedQuote() -> NSData { + return NSKeyedArchiver.archivedDataWithRootObject(quote) + } + + func unarchive(archive: NSData) -> FXQuote? { + return NSKeyedUnarchiver.unarchiveObjectWithData(archive) as? FXQuote + } + + func test__quote_encodes() { + quote = FXQuote(rate: 1.5409) + XCTAssertEqual(unarchive(archiveEncodedQuote())!.rate, quote.rate) + } +} diff --git a/Tests/MoneyTests.swift b/Tests/MoneyTests.swift index 18ab6db..d80f506 100644 --- a/Tests/MoneyTests.swift +++ b/Tests/MoneyTests.swift @@ -9,6 +9,18 @@ import XCTest @testable import Money +func createGarbageData() -> NSData { + return MoneyTestHelper.createGarbageData() +} + +class MoneyTestHelper { + static func createGarbageData() -> NSData { + let path = NSBundle(forClass: MoneyTestHelper.self).pathForResource("Troll", ofType: "png") + let data = NSData(contentsOfFile: path!) + return data! + } +} + class MoneyInitializerTests: XCTestCase { var money: Money! From f2bac6a5796f1305a3cfa711dfde177e19818dba Mon Sep 17 00:00:00 2001 From: Daniel Thorpe Date: Fri, 6 Nov 2015 13:31:39 +0000 Subject: [PATCH 05/11] [MNY-16]: Updates the FX API to provide quote. --- Money/FX.swift | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/Money/FX.swift b/Money/FX.swift index 2c52501..300f92a 100644 --- a/Money/FX.swift +++ b/Money/FX.swift @@ -225,27 +225,54 @@ extension FXRemoteProviderType { extension FXRemoteProviderType where BaseMoney.DecimalStorageType == BankersDecimal.DecimalStorageType, CounterMoney.DecimalStorageType == BankersDecimal.DecimalStorageType { - internal static func fxFromQuoteWithBase(base: BaseMoney) -> FXQuote -> CounterMoney { - return { $0.transactionValueForBaseValue(base) } + internal static func fxFromQuoteWithBase(base: BaseMoney) -> FXQuote -> (BaseMoney, FXQuote, CounterMoney) { + return { (base, $0, $0.transactionValueForBaseValue(base)) } } /** - # FX + # FX - Get Quote This is the primary API used to determine for Foreign Exchange transactions. Using the `Yahoo` FX Provider as an example, we would use it like this.. + + Yahoo.quote(100) { result in + guard let (pounds, quote, usd) = result.value else { + error("Received an `FXError`") + } + print("Exchanged \(pounds) into \(usd) with a rate of \(quote.rate)") + } - let gbp: GBP = 100 // We have £100 - Yahoo.fx(gbp) { result in + - parameter base: the `BaseMoney` which is a `MoneyType`. Because it's literal + convertible, this can receive a literal if you're just playing. + - parameter completion: a completion block which receives a `Result`. + The error is an `FXError` value, and the result "value" is a tuple, of the + base money, the quote, and the counter money, or `(BaseMoney, FXQuote, CounterMoney)`. + - returns: an `NSURLSessionDataTask`. + */ + public static func quote(base: BaseMoney, completion: Result<(BaseMoney, FXQuote, CounterMoney), FXError> -> Void) -> NSURLSessionDataTask { + let client = FXServiceProviderNetworkClient(session: session()) + let fxFromQuote = fxFromQuoteWithBase(base) + return client.get(request(), adaptor: quoteFromNetworkResult) { completion($0.map(fxFromQuote)) } + } + + /** + # FX - Get Counter Money + This is a convenience API used to determine for Foreign Exchange transactions. Using the + `Yahoo` FX Provider as an example, we would use it like this.. + + Yahoo.fx(100) { result in guard let usd = result.value?.counter else { print("Received an `FXError`") } print("We have \(usd)") // We have $119 (or whatever) } + - parameter base: the `BaseMoney` which is a `MoneyType`. Because it's literal + convertible, this can receive a literal if you're just playing. + - parameter completion: a completion block which receives a `Result`. + The error is an `FXError` value, and the result "value" is the `CounterMoney`. + - returns: an `NSURLSessionDataTask`. */ public static func fx(base: BaseMoney, completion: Result -> Void) -> NSURLSessionDataTask { - let client = FXServiceProviderNetworkClient(session: session()) - let fxFromQuote = fxFromQuoteWithBase(base) - return client.get(request(), adaptor: quoteFromNetworkResult) { completion($0.map(fxFromQuote)) } + return quote(base) { completion($0.map { $0.2 }) } } } From 01a40a99fa8b9cb222eafe561a91a39baa088d3b Mon Sep 17 00:00:00 2001 From: Daniel Thorpe Date: Fri, 6 Nov 2015 13:39:28 +0000 Subject: [PATCH 06/11] [MNY-16]: Updates the README to include the quote function. --- README.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4a33531..e2e1e79 100644 --- a/README.md +++ b/README.md @@ -66,15 +66,28 @@ To represent a foreign exchange transaction, i.e. converting `USD` to `EUR`, use The following code snippet represent a currency exchange using Yahoo’s currency converter. +```swift +Yahoo.quote(100) { result in + if let (dollars, quote, euros) = result.value { + print("Exchanged \(dollars) into \(euros) with a rate of \(quote.rate)") + } +} +``` + +> Exchanged US$ 100.00 into € 92.15 with a rate of 0.9215 + +The result, delivered asynchronously, uses [`Result`](http://github.com/antitypical/Result) to encapsulate either a tuple value `(BaseMoney, FXQuote, CounterMoney)` or an `FXError` value. Obviously, in real code - you’d need to check for errors ;) + +There is a neat convenience function which just returns the `CounterMoney` as its `Result` value type. + ```swift Yahoo.fx(100) { euros in print("You got \(euros)") } ``` -> You got .Success(€ 92.00) +> You got .Success(€ 92.15) -The result, delivered asynchronously, uses [`Result`](http://github.com/antitypical/Result) to encapsulate either the `FXProviderType.CounterMoney` or an `FXError` value. Obviously, in real code - you’d need to check for errors ;) ### Creating custom FX service providers From 728fd9e75ca972097d7188ce71a1be53b043a482 Mon Sep 17 00:00:00 2001 From: Daniel Thorpe Date: Fri, 6 Nov 2015 13:40:33 +0000 Subject: [PATCH 07/11] [MNY-16]: Adds a link to a blog post. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e2e1e79..bef3c83 100644 --- a/README.md +++ b/README.md @@ -238,6 +238,8 @@ Daniel Thorpe [@danthorpe](https://twitter.com/danthorpe). Feel free to get in contact if you have questions, queries, or need help. +I wrote an introductory blog post about money [here](http://danthorpe.me/posts/money.html). + ## License Money is available under the MIT license. See the LICENSE file for more info. From 162f18d5b2ca32ab4a4747acda5eba2690278279 Mon Sep 17 00:00:00 2001 From: Daniel Thorpe Date: Fri, 6 Nov 2015 14:11:01 +0000 Subject: [PATCH 08/11] [MNY-17]: Cleans up DecimalNumberType protocol --- Money/Decimal/Decimal.swift | 21 ++--- Money/Decimal/DecimalNumberType.swift | 113 +++++++++++++++----------- Money/Money.swift | 27 +++--- 3 files changed, 89 insertions(+), 72 deletions(-) diff --git a/Money/Decimal/Decimal.swift b/Money/Decimal/Decimal.swift index aaad6f7..ad6ad28 100644 --- a/Money/Decimal/Decimal.swift +++ b/Money/Decimal/Decimal.swift @@ -36,6 +36,7 @@ import ValueCoding and scale rules for base 10 decimal arithmetic. */ public struct _Decimal: DecimalNumberType { + public typealias DecimalNumberBehavior = Behavior /// Access the underlying decimal storage. @@ -100,8 +101,8 @@ public struct _Decimal: DecimalNumberType { - returns: another instance of this type. */ @warn_unused_result - public func subtract(other: _Decimal, withBehaviors behaviors: NSDecimalNumberBehaviors) -> _Decimal { - return _Decimal(storage: storage.subtract(other.storage, withBehaviors: behaviors)) + public func subtract(other: _Decimal) -> _Decimal { + return _Decimal(storage: storage.subtract(other.storage, withBehaviors: DecimalNumberBehavior.decimalNumberBehaviors)) } /** @@ -112,8 +113,8 @@ public struct _Decimal: DecimalNumberType { - returns: another instance of this type. */ @warn_unused_result - public func add(other: _Decimal, withBehaviors behaviors: NSDecimalNumberBehaviors) -> _Decimal { - return _Decimal(storage: storage.add(other.storage, withBehaviors: behaviors)) + public func add(other: _Decimal) -> _Decimal { + return _Decimal(storage: storage.add(other.storage, withBehaviors: DecimalNumberBehavior.decimalNumberBehaviors)) } /** @@ -124,8 +125,8 @@ public struct _Decimal: DecimalNumberType { - returns: another instance of this type. */ @warn_unused_result - public func multiplyBy(other: _Decimal, withBehaviors behaviors: NSDecimalNumberBehaviors) -> _Decimal { - return _Decimal(storage: storage.multiplyBy(other.storage, withBehaviors: behaviors)) + public func multiplyBy(other: _Decimal) -> _Decimal { + return _Decimal(storage: storage.multiplyBy(other.storage, withBehaviors: DecimalNumberBehavior.decimalNumberBehaviors)) } /** @@ -136,8 +137,8 @@ public struct _Decimal: DecimalNumberType { - returns: another instance of this type. */ @warn_unused_result - public func divideBy(other: _Decimal, withBehaviors behaviors: NSDecimalNumberBehaviors) -> _Decimal { - return _Decimal(storage: storage.divideBy(other.storage, withBehaviors: behaviors)) + public func divideBy(other: _Decimal) -> _Decimal { + return _Decimal(storage: storage.divideBy(other.storage, withBehaviors: DecimalNumberBehavior.decimalNumberBehaviors)) } /** @@ -148,8 +149,8 @@ public struct _Decimal: DecimalNumberType { - returns: another instance of this type. */ @warn_unused_result - public func remainder(other: _Decimal, withBehaviors behaviors: NSDecimalNumberBehaviors) -> _Decimal { - return _Decimal(storage: storage.remainder(other.storage, withBehaviors: behaviors)) + public func remainder(other: _Decimal) -> _Decimal { + return _Decimal(storage: storage.remainder(other.storage, withBehaviors: DecimalNumberBehavior.decimalNumberBehaviors)) } } diff --git a/Money/Decimal/DecimalNumberType.swift b/Money/Decimal/DecimalNumberType.swift index abf95e6..7a00b44 100644 --- a/Money/Decimal/DecimalNumberType.swift +++ b/Money/Decimal/DecimalNumberType.swift @@ -27,33 +27,53 @@ import Foundation +/** + + # DecimalNumberBehaviorType + + Defines the decimal number behavior, i.e. `NSDecimalNumberBehaviors` + of the type. + + */ public protocol DecimalNumberBehaviorType { /// Specify the decimal number (i.e. rounding, scale etc) for base 10 calculations static var decimalNumberBehaviors: NSDecimalNumberBehaviors { get } } -public struct DecimalNumberBehavior { +/** - private static func behaviorWithRoundingMode(mode: NSRoundingMode) -> NSDecimalNumberBehaviors { - return NSDecimalNumberHandler(roundingMode: mode, scale: 38, raiseOnExactness: false, raiseOnOverflow: true, raiseOnUnderflow: true, raiseOnDivideByZero: true) - } + # DecimalNumberBehavior + + This is a name space of types which conform to `DecimalNumberBehaviorType` + with common rounding modes. All have maximum precision, of 38 significant + digits. +*/ +public struct DecimalNumberBehavior { + /// Plain rounding mode public struct Plain: DecimalNumberBehaviorType { public static let decimalNumberBehaviors = DecimalNumberBehavior.behaviorWithRoundingMode(.RoundPlain) } + /// Round down mode public struct RoundDown: DecimalNumberBehaviorType { public static let decimalNumberBehaviors = DecimalNumberBehavior.behaviorWithRoundingMode(.RoundDown) } + /// Round up mode public struct RoundUp: DecimalNumberBehaviorType { public static let decimalNumberBehaviors = DecimalNumberBehavior.behaviorWithRoundingMode(.RoundUp) } + /// Bankers rounding mode, see `NSRoundingMode.RoundBankers` for info. public struct Bankers: DecimalNumberBehaviorType { public static let decimalNumberBehaviors = DecimalNumberBehavior.behaviorWithRoundingMode(.RoundBankers) } + + private static func behaviorWithRoundingMode(mode: NSRoundingMode, scale: Int16 = 38) -> NSDecimalNumberBehaviors { + return NSDecimalNumberHandler(roundingMode: mode, scale: 38, raiseOnExactness: false, raiseOnOverflow: true, raiseOnUnderflow: true, raiseOnDivideByZero: true) + } } @@ -93,31 +113,28 @@ public protocol DecimalNumberType: SignedNumberType, IntegerLiteralConvertible, Subtract a matching `DecimalNumberType` from the receiver. - parameter other: another instance of this type. - - parameter behaviors: an optional NSDecimalNumberBehaviors? - returns: another instance of this type. */ @warn_unused_result - func subtract(_: Self, withBehaviors: NSDecimalNumberBehaviors) -> Self + func subtract(_: Self) -> Self /** Add a matching `DecimalNumberType` to the receiver. - parameter other: another instance of this type. - - parameter behaviors: an optional NSDecimalNumberBehaviors? - returns: another instance of this type. */ @warn_unused_result - func add(_: Self, withBehaviors: NSDecimalNumberBehaviors) -> Self + func add(_: Self) -> Self /** Multiply a matching `DecimalNumberType` with the receiver. - parameter other: another instance of this type. - - parameter behaviors: an optional NSDecimalNumberBehaviors? - returns: another instance of this type. */ @warn_unused_result - func multiplyBy(_: Self, withBehaviors: NSDecimalNumberBehaviors) -> Self + func multiplyBy(_: Self) -> Self /** Multiply another `DecimalNumberType` with the receiver. The other @@ -125,21 +142,19 @@ public protocol DecimalNumberType: SignedNumberType, IntegerLiteralConvertible, this `DecimalNumberType`. - parameter other: another `DecimalNumberType` value of different type. - - parameter behaviors: an optional NSDecimalNumberBehaviors? - returns: a different `DecimalNumberType` value. */ @warn_unused_result - func multiplyBy(_: Other, withBehaviors: NSDecimalNumberBehaviors) -> Other + func multiplyBy(_: Other) -> Other /** Divide the receiver by a matching `DecimalNumberType`. - parameter other: another instance of this type. - - parameter behaviors: an optional NSDecimalNumberBehaviors? - returns: another instance of this type. */ @warn_unused_result - func divideBy(_: Self, withBehaviors: NSDecimalNumberBehaviors) -> Self + func divideBy(_: Self) -> Self /** Divide the receiver by another `DecimalNumberType`. The other @@ -147,28 +162,49 @@ public protocol DecimalNumberType: SignedNumberType, IntegerLiteralConvertible, this `DecimalNumberType`. - parameter other: another `DecimalNumberType` value of different type. - - parameter behaviors: an optional NSDecimalNumberBehaviors? - returns: another instance of this type. */ @warn_unused_result - func divideBy(_: Other, withBehaviors: NSDecimalNumberBehaviors) -> Other + func divideBy(_: Other) -> Other /** The remainder of dividing another `DecimalNumberType` into the receiver. - parameter other: another instance of this type. - - parameter behaviors: an optional NSDecimalNumberBehaviors? - returns: another instance of this type. */ @warn_unused_result - func remainder(_: Self, withBehaviors: NSDecimalNumberBehaviors) -> Self + func remainder(_: Self) -> Self } +public extension DecimalNumberType where DecimalStorageType == NSDecimalNumber { + + @warn_unused_result + func multiplyBy(other: Other) -> Other { + return Other(storage: storage.multiplyBy(other.storage, withBehaviors: Other.DecimalNumberBehavior.decimalNumberBehaviors) ) + } + + @warn_unused_result + func divideBy(other: Other) -> Other { + return Other(storage: storage.divideBy(other.storage, withBehaviors: Other.DecimalNumberBehavior.decimalNumberBehaviors)) + } +} + +extension DecimalNumberType where Self.IntegerLiteralType == Int { + + /// Get the reciprocal of the receiver. + public var reciprocal: Self { + return Self(integerLiteral: 1).divideBy(self) + } +} + +// MARK: - Operators + // MARK: - Subtraction @warn_unused_result public func -(lhs: T, rhs: T) -> T { - return lhs.subtract(rhs, withBehaviors: T.DecimalNumberBehavior.decimalNumberBehaviors) + return lhs.subtract(rhs) } @warn_unused_result @@ -191,18 +227,11 @@ public func -(lhs: T.FloatLiteralType, rhs: T) -> T { return T(floatLiteral: lhs) - rhs } -// MARK: - Remainder - -@warn_unused_result -public func %(lhs: T, rhs: T) -> T { - return lhs.remainder(rhs, withBehaviors: T.DecimalNumberBehavior.decimalNumberBehaviors) -} - // MARK: - Addition @warn_unused_result public func +(lhs: T, rhs: T) -> T { - return lhs.add(rhs, withBehaviors: T.DecimalNumberBehavior.decimalNumberBehaviors) + return lhs.add(rhs) } @warn_unused_result @@ -229,7 +258,7 @@ public func +(lhs: T.FloatLiteralType, rhs: T) -> T { @warn_unused_result public func *(lhs: T, rhs: T) -> T { - return lhs.multiplyBy(rhs, withBehaviors: T.DecimalNumberBehavior.decimalNumberBehaviors) + return lhs.multiplyBy(rhs) } @warn_unused_result @@ -257,14 +286,14 @@ public func *(lhs: T, rhs: V) -> V { - return lhs.multiplyBy(rhs, withBehaviors: V.DecimalNumberBehavior.decimalNumberBehaviors) + return lhs.multiplyBy(rhs) } // MARK: - Division @warn_unused_result public func /(lhs: T, rhs: T) -> T { - return lhs.divideBy(rhs, withBehaviors: T.DecimalNumberBehavior.decimalNumberBehaviors) + return lhs.divideBy(rhs) } @warn_unused_result @@ -282,28 +311,14 @@ public func /(lhs: T, rhs: V) -> V { - return lhs.divideBy(rhs, withBehaviors: V.DecimalNumberBehavior.decimalNumberBehaviors) -} - -extension DecimalNumberType where DecimalStorageType == NSDecimalNumber { - - @warn_unused_result - public func multiplyBy(other: Other, withBehaviors behaviors: NSDecimalNumberBehaviors) -> Other { - return Other(storage: storage.multiplyBy(other.storage, withBehaviors: behaviors)) - } - - @warn_unused_result - public func divideBy(other: Other, withBehaviors behaviors: NSDecimalNumberBehaviors) -> Other { - return Other(storage: storage.divideBy(other.storage, withBehaviors: behaviors)) - } + return lhs.divideBy(rhs) } -extension DecimalNumberType where Self.IntegerLiteralType == Int { +// MARK: - Remainder - /// Get the reciprocal of the receiver. - public var reciprocal: Self { - return Self(integerLiteral: 1).divideBy(self, withBehaviors: DecimalNumberBehavior.decimalNumberBehaviors) - } +@warn_unused_result +public func %(lhs: T, rhs: T) -> T { + return lhs.remainder(rhs) } diff --git a/Money/Money.swift b/Money/Money.swift index 7e5e7f3..f82e7fb 100644 --- a/Money/Money.swift +++ b/Money/Money.swift @@ -121,8 +121,8 @@ public struct _Money: MoneyType { - returns: another instance of this type. */ @warn_unused_result - public func subtract(other: _Money, withBehaviors behaviors: NSDecimalNumberBehaviors) -> _Money { - return _Money(decimal.subtract(other.decimal, withBehaviors: behaviors)) + public func subtract(other: _Money) -> _Money { + return _Money(decimal.subtract(other.decimal)) } /** @@ -133,8 +133,8 @@ public struct _Money: MoneyType { - returns: another instance of this type. */ @warn_unused_result - public func add(other: _Money, withBehaviors behaviors: NSDecimalNumberBehaviors) -> _Money { - return _Money(decimal.add(other.decimal, withBehaviors: behaviors)) + public func add(other: _Money) -> _Money { + return _Money(decimal.add(other.decimal)) } /** @@ -146,8 +146,8 @@ public struct _Money: MoneyType { */ @warn_unused_result - public func multiplyBy(other: _Money, withBehaviors behaviors: NSDecimalNumberBehaviors) -> _Money { - return _Money(decimal.multiplyBy(other.decimal, withBehaviors: behaviors)) + public func multiplyBy(other: _Money) -> _Money { + return _Money(decimal.multiplyBy(other.decimal)) } /** @@ -158,8 +158,8 @@ public struct _Money: MoneyType { - returns: another instance of this type. */ @warn_unused_result - public func divideBy(other: _Money, withBehaviors behaviors: NSDecimalNumberBehaviors) -> _Money { - return _Money(decimal.divideBy(other.decimal, withBehaviors: behaviors)) + public func divideBy(other: _Money) -> _Money { + return _Money(decimal.divideBy(other.decimal)) } /** @@ -170,8 +170,8 @@ public struct _Money: MoneyType { - returns: another instance of this type. */ @warn_unused_result - public func remainder(other: _Money, withBehaviors behaviors: NSDecimalNumberBehaviors) -> _Money { - return _Money(decimal.remainder(other.decimal, withBehaviors: behaviors)) + public func remainder(other: _Money) -> _Money { + return _Money(decimal.remainder(other.decimal)) } } @@ -222,15 +222,16 @@ extension _Money: CustomStringConvertible { // MARK: - MoneyType Extension -extension MoneyType where DecimalStorageType == BankersDecimal.DecimalStorageType { +public extension MoneyType where DecimalStorageType == BankersDecimal.DecimalStorageType { /** Use a `BankersDecimal` to convert the receive into another `MoneyType`. To use this API the underlying `DecimalStorageType`s between the receiver, the other `MoneyType` must both be the same a that of `BankersDecimal` (which luckily they are). */ - public func convertWithRate(rate: BankersDecimal) -> Other { - return multiplyBy(Other(storage: rate.storage), withBehaviors: Other.DecimalNumberBehavior.decimalNumberBehaviors) + @warn_unused_result + func convertWithRate(rate: BankersDecimal) -> Other { + return multiplyBy(Other(storage: rate.storage)) } } From af17e3366e484aa2b925293a97af2f693a50bc94 Mon Sep 17 00:00:00 2001 From: Daniel Thorpe Date: Fri, 6 Nov 2015 14:21:18 +0000 Subject: [PATCH 09/11] [release]: Bumps the version to 1.1.0 --- Money.podspec | 2 +- Supporting Files/Money.xcconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Money.podspec b/Money.podspec index 43a484f..9ce012a 100644 --- a/Money.podspec +++ b/Money.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Money" - s.version = "1.0.0" + s.version = "1.1.0" s.summary = "Swift types for working with Money." s.description = <<-DESC diff --git a/Supporting Files/Money.xcconfig b/Supporting Files/Money.xcconfig index 20eff10..1d3979c 100644 --- a/Supporting Files/Money.xcconfig +++ b/Supporting Files/Money.xcconfig @@ -6,7 +6,7 @@ // // -MONEY_VERSION = 1.0.0 +MONEY_VERSION = 1.1.0 APPLICATION_EXTENSION_API_ONLY = YES INFOPLIST_FILE = $(SRCROOT)/Supporting Files/Info.plist From 7f135ce65acde3889fb38b4d8b55af3d92600e9a Mon Sep 17 00:00:00 2001 From: Daniel Thorpe Date: Fri, 6 Nov 2015 14:27:13 +0000 Subject: [PATCH 10/11] [release]: Updates CHANGELOG --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c33ee7..bf14cbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 1.1.0 +1. [[MNY-16](https://github.com/danthorpe/Money/pull/16)]: Grab bag of minor issues post 1.0 release. + * Cleans up some minor mistakes (spelling etc). + * Adds `NSCoding` conformance to `FXQuote` - so it can be persisted if needed. + * Adds `FXRemoteProviderType.quote(: BaseMoney, completion: Result<(BaseMoney, FXQuote, CounterMoney), FXError> -> Void) -> NSURLSessionDataTask` API. This is the nuts and bolts of the FX provider now. It returns as its result, the base money (i.e. the input), the quote (which includes the rate), and the counter money (i.e. the output). The `fx` method still exists, and it just unwraps the tuple to return the counter money. See the updated README. +2. [[MNY-17](https://github.com/danthorpe/Money/pull/17)]: There was an oversight in the functions in `DecimalNumberType` which accepts `NSDecimalNumberBehaviors` as an argument. These were unnecessary so I’ve removed them. Hence the minor version bump. # 1.0.0 🎉🐝 Initial release of Money. From 13d4281f75113ec1c5d84e0e49a89ae1807b38cd Mon Sep 17 00:00:00 2001 From: Daniel Thorpe Date: Fri, 6 Nov 2015 14:31:44 +0000 Subject: [PATCH 11/11] [release]: Updates README to include import statment --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index bef3c83..f9ed2d4 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ Money is a Swift framework for iOS, watchOS, tvOS and OS X. It provides types an The Money framework defines the type `Money`, which represents money in the device’s current locale. The following code: ```swift +import Money + let money: Money = 100 print("I'll give \(money) to charity.”) ```