diff --git a/.jazzy.yaml b/.jazzy.yaml index e471087..0aef0a6 100644 --- a/.jazzy.yaml +++ b/.jazzy.yaml @@ -1,7 +1,7 @@ author_name: Daniel Thorpe author_url: http://danthorpe.me module_name: Money -module_version: 1.4.0 +module_version: 1.5.0 github_url: https://github.com/danthorpe/Money readme: README.md podspec: Money.podspec diff --git a/Cartfile b/Cartfile index 2e4b6cd..372cfc1 100644 --- a/Cartfile +++ b/Cartfile @@ -1,3 +1 @@ github "danthorpe/ValueCoding" -github "antitypical/Result" >= 1.0 -github "SwiftyJSON/SwiftyJSON" diff --git a/Cartfile.private b/Cartfile.private deleted file mode 100644 index d3f519b..0000000 --- a/Cartfile.private +++ /dev/null @@ -1 +0,0 @@ -github "venmo/DVR" diff --git a/Cartfile.resolved b/Cartfile.resolved index a6a393a..9055530 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,4 +1 @@ -github "venmo/DVR" "v0.2.0" -github "antitypical/Result" "1.0.1" -github "SwiftyJSON/SwiftyJSON" "2.3.3" -github "danthorpe/ValueCoding" "1.1.1" +github "danthorpe/ValueCoding" "1.2.0" diff --git a/Money.podspec b/Money.podspec index 08ea2f4..3902205 100644 --- a/Money.podspec +++ b/Money.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Money" - s.version = "1.4.2" + s.version = "1.5.0" s.summary = "Swift types for working with Money." s.description = <<-DESC @@ -34,7 +34,6 @@ Pod::Spec.new do |s| s.tvos.exclude_files = [ 'Money/iOS' ] s.dependency 'ValueCoding' - s.dependency 'Result' - s.dependency 'SwiftyJSON' + end diff --git a/Money.xcodeproj/project.pbxproj b/Money.xcodeproj/project.pbxproj index 72535d6..f7f20cb 100644 --- a/Money.xcodeproj/project.pbxproj +++ b/Money.xcodeproj/project.pbxproj @@ -38,64 +38,29 @@ 6557F4C91BEB7F3D003CD2BF /* ValueCoding.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6557F4C81BEB7F3D003CD2BF /* ValueCoding.framework */; }; 6557F4CB1BEB7F46003CD2BF /* ValueCoding.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6557F4CA1BEB7F46003CD2BF /* ValueCoding.framework */; }; 6557F4CD1BEB7F51003CD2BF /* ValueCoding.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6557F4CC1BEB7F51003CD2BF /* ValueCoding.framework */; }; - 6564094D1BEABA6100F82B4D /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6564094C1BEABA6100F82B4D /* SwiftyJSON.framework */; }; - 6564094F1BEABA6E00F82B4D /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6564094E1BEABA6E00F82B4D /* SwiftyJSON.framework */; }; - 656409511BEABA7A00F82B4D /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 656409501BEABA7A00F82B4D /* SwiftyJSON.framework */; }; - 656409531BEABA8400F82B4D /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 656409521BEABA8400F82B4D /* SwiftyJSON.framework */; }; - 658863BD1BEA34ED003482ED /* DVR.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 658863BC1BEA34ED003482ED /* DVR.framework */; }; - 658863BF1BEA3514003482ED /* DVR.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 658863BE1BEA3514003482ED /* DVR.framework */; }; 65B92ADE1BE0E4A700F82024 /* Money.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65B92AD31BE0E4A700F82024 /* Money.framework */; }; 65B92B071BE0E4D800F82024 /* Money.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65B92AFD1BE0E4D800F82024 /* Money.framework */; }; 65B92B231BE0E4E700F82024 /* Money.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65B92B191BE0E4E700F82024 /* Money.framework */; }; 65B92B351BE0E51E00F82024 /* Money.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B92B331BE0E51E00F82024 /* Money.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 65B92B3A1BE0E69500F82024 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 65B92B381BE0E69500F82024 /* Info.plist */; }; 65B92B3C1BE0E70500F82024 /* Money.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B92B331BE0E51E00F82024 /* Money.h */; settings = {ATTRIBUTES = (Public, ); }; }; 65B92B3D1BE0E70500F82024 /* Money.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B92B331BE0E51E00F82024 /* Money.h */; settings = {ATTRIBUTES = (Public, ); }; }; 65B92B3E1BE0E70600F82024 /* Money.h in Headers */ = {isa = PBXBuildFile; fileRef = 65B92B331BE0E51E00F82024 /* Money.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 65D3055A1BE94F860032D99F /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65D305591BE94F860032D99F /* Result.framework */; }; - 65D3055B1BE94FA70032D99F /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65D305571BE94E850032D99F /* Result.framework */; }; - 65D3055D1BE94FD40032D99F /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65D3055C1BE94FD40032D99F /* Result.framework */; }; - 65D305601BE955020032D99F /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65D3055F1BE955020032D99F /* Result.framework */; }; 65DD22AE1BFA10F10054F62D /* BitcoinTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22A01BFA10DF0054F62D /* BitcoinTests.swift */; }; 65DD22AF1BFA10F10054F62D /* DecimalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22A11BFA10DF0054F62D /* DecimalTests.swift */; }; - 65DD22B01BFA10F10054F62D /* FXOpenExchangeRatesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22A71BFA10DF0054F62D /* FXOpenExchangeRatesTests.swift */; }; - 65DD22B11BFA10F10054F62D /* FXTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22A81BFA10DF0054F62D /* FXTests.swift */; }; - 65DD22B21BFA10F10054F62D /* FXYahooTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22A91BFA10DF0054F62D /* FXYahooTests.swift */; }; 65DD22B31BFA10F10054F62D /* MoneyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22AA1BFA10DF0054F62D /* MoneyTests.swift */; }; 65DD22B41BFA10F10054F62D /* NSDecimalNumberTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22AB1BFA10DF0054F62D /* NSDecimalNumberTests.swift */; }; 65DD22B51BFA10F10054F62D /* NSDecimalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22AC1BFA10DF0054F62D /* NSDecimalTests.swift */; }; 65DD22B61BFA10F20054F62D /* BitcoinTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22A01BFA10DF0054F62D /* BitcoinTests.swift */; }; 65DD22B71BFA10F20054F62D /* DecimalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22A11BFA10DF0054F62D /* DecimalTests.swift */; }; - 65DD22B81BFA10F20054F62D /* FXOpenExchangeRatesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22A71BFA10DF0054F62D /* FXOpenExchangeRatesTests.swift */; }; - 65DD22B91BFA10F20054F62D /* FXTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22A81BFA10DF0054F62D /* FXTests.swift */; }; - 65DD22BA1BFA10F20054F62D /* FXYahooTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22A91BFA10DF0054F62D /* FXYahooTests.swift */; }; 65DD22BB1BFA10F20054F62D /* MoneyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22AA1BFA10DF0054F62D /* MoneyTests.swift */; }; 65DD22BC1BFA10F20054F62D /* NSDecimalNumberTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22AB1BFA10DF0054F62D /* NSDecimalNumberTests.swift */; }; 65DD22BD1BFA10F20054F62D /* NSDecimalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22AC1BFA10DF0054F62D /* NSDecimalTests.swift */; }; 65DD22BE1BFA10F30054F62D /* BitcoinTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22A01BFA10DF0054F62D /* BitcoinTests.swift */; }; 65DD22BF1BFA10F30054F62D /* DecimalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22A11BFA10DF0054F62D /* DecimalTests.swift */; }; - 65DD22C01BFA10F30054F62D /* FXOpenExchangeRatesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22A71BFA10DF0054F62D /* FXOpenExchangeRatesTests.swift */; }; - 65DD22C11BFA10F30054F62D /* FXTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22A81BFA10DF0054F62D /* FXTests.swift */; }; - 65DD22C21BFA10F30054F62D /* FXYahooTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22A91BFA10DF0054F62D /* FXYahooTests.swift */; }; 65DD22C31BFA10F30054F62D /* MoneyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22AA1BFA10DF0054F62D /* MoneyTests.swift */; }; 65DD22C41BFA10F30054F62D /* NSDecimalNumberTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22AB1BFA10DF0054F62D /* NSDecimalNumberTests.swift */; }; 65DD22C51BFA10F30054F62D /* NSDecimalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD22AC1BFA10DF0054F62D /* NSDecimalTests.swift */; }; 65DD22C61BFA10F60054F62D /* ApplePayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DD229E1BFA10DF0054F62D /* ApplePayTests.swift */; }; - 65DD22C81BFA110D0054F62D /* CEX.IO BTCUSD.json in Resources */ = {isa = PBXBuildFile; fileRef = 65DD22A31BFA10DF0054F62D /* CEX.IO BTCUSD.json */; }; - 65DD22C91BFA110D0054F62D /* CEX.IO USDBTC.json in Resources */ = {isa = PBXBuildFile; fileRef = 65DD22A41BFA10DF0054F62D /* CEX.IO USDBTC.json */; }; - 65DD22CA1BFA110D0054F62D /* OpenExchangeRates.org USDEUR.json in Resources */ = {isa = PBXBuildFile; fileRef = 65DD22A51BFA10DF0054F62D /* OpenExchangeRates.org USDEUR.json */; }; - 65DD22CB1BFA110D0054F62D /* Yahoo GBPUSD.json in Resources */ = {isa = PBXBuildFile; fileRef = 65DD22A61BFA10DF0054F62D /* Yahoo GBPUSD.json */; }; - 65DD22CC1BFA11150054F62D /* CEX.IO BTCUSD.json in Resources */ = {isa = PBXBuildFile; fileRef = 65DD22A31BFA10DF0054F62D /* CEX.IO BTCUSD.json */; }; - 65DD22CD1BFA11150054F62D /* CEX.IO USDBTC.json in Resources */ = {isa = PBXBuildFile; fileRef = 65DD22A41BFA10DF0054F62D /* CEX.IO USDBTC.json */; }; - 65DD22CE1BFA11150054F62D /* OpenExchangeRates.org USDEUR.json in Resources */ = {isa = PBXBuildFile; fileRef = 65DD22A51BFA10DF0054F62D /* OpenExchangeRates.org USDEUR.json */; }; - 65DD22CF1BFA11150054F62D /* Yahoo GBPUSD.json in Resources */ = {isa = PBXBuildFile; fileRef = 65DD22A61BFA10DF0054F62D /* Yahoo GBPUSD.json */; }; - 65DD22D01BFA111B0054F62D /* CEX.IO BTCUSD.json in Resources */ = {isa = PBXBuildFile; fileRef = 65DD22A31BFA10DF0054F62D /* CEX.IO BTCUSD.json */; }; - 65DD22D11BFA111B0054F62D /* CEX.IO USDBTC.json in Resources */ = {isa = PBXBuildFile; fileRef = 65DD22A41BFA10DF0054F62D /* CEX.IO USDBTC.json */; }; - 65DD22D21BFA111B0054F62D /* OpenExchangeRates.org USDEUR.json in Resources */ = {isa = PBXBuildFile; fileRef = 65DD22A51BFA10DF0054F62D /* OpenExchangeRates.org USDEUR.json */; }; - 65DD22D31BFA111B0054F62D /* Yahoo GBPUSD.json in Resources */ = {isa = PBXBuildFile; fileRef = 65DD22A61BFA10DF0054F62D /* Yahoo GBPUSD.json */; }; - 65DD22D41BFA12810054F62D /* Troll.png in Resources */ = {isa = PBXBuildFile; fileRef = 65DD22AD1BFA10DF0054F62D /* Troll.png */; }; - 65DD22D51BFA12870054F62D /* Troll.png in Resources */ = {isa = PBXBuildFile; fileRef = 65DD22AD1BFA10DF0054F62D /* Troll.png */; }; - 65DD22D61BFA128D0054F62D /* Troll.png in Resources */ = {isa = PBXBuildFile; fileRef = 65DD22AD1BFA10DF0054F62D /* Troll.png */; }; 65DEE3351BFA0F370043A718 /* ApplePay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3251BFA0F370043A718 /* ApplePay.swift */; }; 65DEE3391BFA0F370043A718 /* Autogenerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3271BFA0F370043A718 /* Autogenerated.swift */; }; 65DEE33A1BFA0F370043A718 /* Autogenerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3271BFA0F370043A718 /* Autogenerated.swift */; }; @@ -125,18 +90,6 @@ 65DEE3521BFA0F370043A718 /* Bitcoin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE32F1BFA0F370043A718 /* Bitcoin.swift */; }; 65DEE3531BFA0F370043A718 /* Bitcoin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE32F1BFA0F370043A718 /* Bitcoin.swift */; }; 65DEE3541BFA0F370043A718 /* Bitcoin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE32F1BFA0F370043A718 /* Bitcoin.swift */; }; - 65DEE3551BFA0F370043A718 /* FX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3301BFA0F370043A718 /* FX.swift */; }; - 65DEE3561BFA0F370043A718 /* FX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3301BFA0F370043A718 /* FX.swift */; }; - 65DEE3571BFA0F370043A718 /* FX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3301BFA0F370043A718 /* FX.swift */; }; - 65DEE3581BFA0F370043A718 /* FX.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3301BFA0F370043A718 /* FX.swift */; }; - 65DEE3591BFA0F370043A718 /* OpenExchangeRates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3311BFA0F370043A718 /* OpenExchangeRates.swift */; }; - 65DEE35A1BFA0F370043A718 /* OpenExchangeRates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3311BFA0F370043A718 /* OpenExchangeRates.swift */; }; - 65DEE35B1BFA0F370043A718 /* OpenExchangeRates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3311BFA0F370043A718 /* OpenExchangeRates.swift */; }; - 65DEE35C1BFA0F370043A718 /* OpenExchangeRates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3311BFA0F370043A718 /* OpenExchangeRates.swift */; }; - 65DEE35D1BFA0F370043A718 /* Yahoo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3321BFA0F370043A718 /* Yahoo.swift */; }; - 65DEE35E1BFA0F370043A718 /* Yahoo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3321BFA0F370043A718 /* Yahoo.swift */; }; - 65DEE35F1BFA0F370043A718 /* Yahoo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3321BFA0F370043A718 /* Yahoo.swift */; }; - 65DEE3601BFA0F370043A718 /* Yahoo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3321BFA0F370043A718 /* Yahoo.swift */; }; 65DEE3611BFA0F370043A718 /* Money.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3331BFA0F370043A718 /* Money.swift */; }; 65DEE3621BFA0F370043A718 /* Money.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3331BFA0F370043A718 /* Money.swift */; }; 65DEE3631BFA0F370043A718 /* Money.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65DEE3331BFA0F370043A718 /* Money.swift */; }; @@ -208,12 +161,6 @@ 6557F4C81BEB7F3D003CD2BF /* ValueCoding.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ValueCoding.framework; path = Carthage/Build/watchOS/ValueCoding.framework; sourceTree = ""; }; 6557F4CA1BEB7F46003CD2BF /* ValueCoding.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ValueCoding.framework; path = Carthage/Build/tvOS/ValueCoding.framework; sourceTree = ""; }; 6557F4CC1BEB7F51003CD2BF /* ValueCoding.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ValueCoding.framework; path = Carthage/Build/Mac/ValueCoding.framework; sourceTree = ""; }; - 6564094C1BEABA6100F82B4D /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/iOS/SwiftyJSON.framework; sourceTree = ""; }; - 6564094E1BEABA6E00F82B4D /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/watchOS/SwiftyJSON.framework; sourceTree = ""; }; - 656409501BEABA7A00F82B4D /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/tvOS/SwiftyJSON.framework; sourceTree = ""; }; - 656409521BEABA8400F82B4D /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/Mac/SwiftyJSON.framework; sourceTree = ""; }; - 658863BC1BEA34ED003482ED /* DVR.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DVR.framework; path = Carthage/Build/iOS/DVR.framework; sourceTree = ""; }; - 658863BE1BEA3514003482ED /* DVR.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DVR.framework; path = Carthage/Build/Mac/DVR.framework; sourceTree = ""; }; 65A876D61BE6491800E26F22 /* Generate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Generate.swift; path = "Supporting Files/Generate.swift"; sourceTree = SOURCE_ROOT; }; 65B92AD31BE0E4A700F82024 /* Money.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Money.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 65B92ADD1BE0E4A700F82024 /* Money-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Money-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -226,24 +173,12 @@ 65B92B331BE0E51E00F82024 /* Money.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Money.h; path = "Supporting Files/Money.h"; sourceTree = SOURCE_ROOT; }; 65B92B361BE0E57800F82024 /* Money.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Money.xcconfig; path = "Supporting Files/Money.xcconfig"; sourceTree = SOURCE_ROOT; }; 65B92B381BE0E69500F82024 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 65D305571BE94E850032D99F /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/tvOS/Result.framework; sourceTree = ""; }; - 65D305591BE94F860032D99F /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/watchOS/Result.framework; sourceTree = ""; }; - 65D3055C1BE94FD40032D99F /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/Mac/Result.framework; sourceTree = ""; }; - 65D3055F1BE955020032D99F /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/iOS/Result.framework; sourceTree = ""; }; 65DD229E1BFA10DF0054F62D /* ApplePayTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplePayTests.swift; sourceTree = ""; }; 65DD22A01BFA10DF0054F62D /* BitcoinTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BitcoinTests.swift; sourceTree = ""; }; 65DD22A11BFA10DF0054F62D /* DecimalTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecimalTests.swift; sourceTree = ""; }; - 65DD22A31BFA10DF0054F62D /* CEX.IO BTCUSD.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "CEX.IO BTCUSD.json"; sourceTree = ""; }; - 65DD22A41BFA10DF0054F62D /* CEX.IO USDBTC.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "CEX.IO USDBTC.json"; sourceTree = ""; }; - 65DD22A51BFA10DF0054F62D /* OpenExchangeRates.org USDEUR.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "OpenExchangeRates.org USDEUR.json"; sourceTree = ""; }; - 65DD22A61BFA10DF0054F62D /* Yahoo GBPUSD.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "Yahoo GBPUSD.json"; sourceTree = ""; }; - 65DD22A71BFA10DF0054F62D /* FXOpenExchangeRatesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FXOpenExchangeRatesTests.swift; sourceTree = ""; }; - 65DD22A81BFA10DF0054F62D /* FXTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FXTests.swift; sourceTree = ""; }; - 65DD22A91BFA10DF0054F62D /* FXYahooTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FXYahooTests.swift; sourceTree = ""; }; 65DD22AA1BFA10DF0054F62D /* MoneyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoneyTests.swift; sourceTree = ""; }; 65DD22AB1BFA10DF0054F62D /* NSDecimalNumberTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDecimalNumberTests.swift; sourceTree = ""; }; 65DD22AC1BFA10DF0054F62D /* NSDecimalTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDecimalTests.swift; sourceTree = ""; }; - 65DD22AD1BFA10DF0054F62D /* Troll.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Troll.png; sourceTree = ""; }; 65DEE3251BFA0F370043A718 /* ApplePay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplePay.swift; sourceTree = ""; }; 65DEE3271BFA0F370043A718 /* Autogenerated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Autogenerated.swift; sourceTree = ""; }; 65DEE3281BFA0F370043A718 /* Currency.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Currency.swift; sourceTree = ""; }; @@ -252,9 +187,6 @@ 65DEE32C1BFA0F370043A718 /* NSDecimalExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDecimalExtensions.swift; sourceTree = ""; }; 65DEE32D1BFA0F370043A718 /* NSDecimalNumberExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDecimalNumberExtensions.swift; sourceTree = ""; }; 65DEE32F1BFA0F370043A718 /* Bitcoin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bitcoin.swift; sourceTree = ""; }; - 65DEE3301BFA0F370043A718 /* FX.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FX.swift; sourceTree = ""; }; - 65DEE3311BFA0F370043A718 /* OpenExchangeRates.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenExchangeRates.swift; sourceTree = ""; }; - 65DEE3321BFA0F370043A718 /* Yahoo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Yahoo.swift; sourceTree = ""; }; 65DEE3331BFA0F370043A718 /* Money.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Money.swift; sourceTree = ""; }; 65DEE3341BFA0F370043A718 /* Support.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Support.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -264,8 +196,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 65D305601BE955020032D99F /* Result.framework in Frameworks */, - 6564094D1BEABA6100F82B4D /* SwiftyJSON.framework in Frameworks */, 6557F4C71BEB7F32003CD2BF /* ValueCoding.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -274,7 +204,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 658863BD1BEA34ED003482ED /* DVR.framework in Frameworks */, 65B92ADE1BE0E4A700F82024 /* Money.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -283,8 +212,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 65D3055A1BE94F860032D99F /* Result.framework in Frameworks */, - 6564094F1BEABA6E00F82B4D /* SwiftyJSON.framework in Frameworks */, 6557F4C91BEB7F3D003CD2BF /* ValueCoding.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -293,8 +220,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 65D3055B1BE94FA70032D99F /* Result.framework in Frameworks */, - 656409511BEABA7A00F82B4D /* SwiftyJSON.framework in Frameworks */, 6557F4CB1BEB7F46003CD2BF /* ValueCoding.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -311,8 +236,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 65D3055D1BE94FD40032D99F /* Result.framework in Frameworks */, - 656409531BEABA8400F82B4D /* SwiftyJSON.framework in Frameworks */, 6557F4CD1BEB7F51003CD2BF /* ValueCoding.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -322,7 +245,6 @@ buildActionMask = 2147483647; files = ( 65B92B231BE0E4E700F82024 /* Money.framework in Frameworks */, - 658863BF1BEA3514003482ED /* DVR.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -388,16 +310,6 @@ 65D3055E1BE94FE10032D99F /* Dependencies */ = { isa = PBXGroup; children = ( - 658863BE1BEA3514003482ED /* DVR.framework */, - 658863BC1BEA34ED003482ED /* DVR.framework */, - 65D3055F1BE955020032D99F /* Result.framework */, - 65D3055C1BE94FD40032D99F /* Result.framework */, - 65D305591BE94F860032D99F /* Result.framework */, - 65D305571BE94E850032D99F /* Result.framework */, - 656409521BEABA8400F82B4D /* SwiftyJSON.framework */, - 656409501BEABA7A00F82B4D /* SwiftyJSON.framework */, - 6564094E1BEABA6E00F82B4D /* SwiftyJSON.framework */, - 6564094C1BEABA6100F82B4D /* SwiftyJSON.framework */, 6557F4CC1BEB7F51003CD2BF /* ValueCoding.framework */, 6557F4CA1BEB7F46003CD2BF /* ValueCoding.framework */, 6557F4C81BEB7F3D003CD2BF /* ValueCoding.framework */, @@ -417,34 +329,18 @@ 65DD229F1BFA10DF0054F62D /* Shared */ = { isa = PBXGroup; children = ( - 65DD22AD1BFA10DF0054F62D /* Troll.png */, 65579FC51C0288A300C3F8C7 /* AutogeneratedTests.swift */, 65DD22A01BFA10DF0054F62D /* BitcoinTests.swift */, 65579F8B1C01F0C100C3F8C7 /* DecimalNumberTypeTests.swift */, 65DD22A11BFA10DF0054F62D /* DecimalTests.swift */, - 65DD22A71BFA10DF0054F62D /* FXOpenExchangeRatesTests.swift */, - 65DD22A81BFA10DF0054F62D /* FXTests.swift */, - 65DD22A91BFA10DF0054F62D /* FXYahooTests.swift */, 6553909C1C037A1A00610C6F /* LocaleTests.swift */, 65DD22AA1BFA10DF0054F62D /* MoneyTests.swift */, 65DD22AB1BFA10DF0054F62D /* NSDecimalNumberTests.swift */, 65DD22AC1BFA10DF0054F62D /* NSDecimalTests.swift */, - 65DD22A21BFA10DF0054F62D /* DVR Cassettes */, ); path = Shared; sourceTree = ""; }; - 65DD22A21BFA10DF0054F62D /* DVR Cassettes */ = { - isa = PBXGroup; - children = ( - 65DD22A31BFA10DF0054F62D /* CEX.IO BTCUSD.json */, - 65DD22A41BFA10DF0054F62D /* CEX.IO USDBTC.json */, - 65DD22A51BFA10DF0054F62D /* OpenExchangeRates.org USDEUR.json */, - 65DD22A61BFA10DF0054F62D /* Yahoo GBPUSD.json */, - ); - path = "DVR Cassettes"; - sourceTree = ""; - }; 65DEE3241BFA0F370043A718 /* iOS */ = { isa = PBXGroup; children = ( @@ -482,9 +378,6 @@ isa = PBXGroup; children = ( 65DEE32F1BFA0F370043A718 /* Bitcoin.swift */, - 65DEE3301BFA0F370043A718 /* FX.swift */, - 65DEE3311BFA0F370043A718 /* OpenExchangeRates.swift */, - 65DEE3321BFA0F370043A718 /* Yahoo.swift */, ); path = FX; sourceTree = ""; @@ -667,7 +560,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0710; - LastUpgradeCheck = 0710; + LastUpgradeCheck = 0720; TargetAttributes = { 65A876D81BE65FAF00E26F22 = { CreatedOnToolsVersion = 7.1; @@ -724,7 +617,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 65B92B3A1BE0E69500F82024 /* Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -732,11 +624,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 65DD22D41BFA12810054F62D /* Troll.png in Resources */, - 65DD22C81BFA110D0054F62D /* CEX.IO BTCUSD.json in Resources */, - 65DD22C91BFA110D0054F62D /* CEX.IO USDBTC.json in Resources */, - 65DD22CA1BFA110D0054F62D /* OpenExchangeRates.org USDEUR.json in Resources */, - 65DD22CB1BFA110D0054F62D /* Yahoo GBPUSD.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -758,11 +645,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 65DD22D51BFA12870054F62D /* Troll.png in Resources */, - 65DD22CC1BFA11150054F62D /* CEX.IO BTCUSD.json in Resources */, - 65DD22CD1BFA11150054F62D /* CEX.IO USDBTC.json in Resources */, - 65DD22CE1BFA11150054F62D /* OpenExchangeRates.org USDEUR.json in Resources */, - 65DD22CF1BFA11150054F62D /* Yahoo GBPUSD.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -777,11 +659,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 65DD22D61BFA128D0054F62D /* Troll.png in Resources */, - 65DD22D01BFA111B0054F62D /* CEX.IO BTCUSD.json in Resources */, - 65DD22D11BFA111B0054F62D /* CEX.IO USDBTC.json in Resources */, - 65DD22D21BFA111B0054F62D /* OpenExchangeRates.org USDEUR.json in Resources */, - 65DD22D31BFA111B0054F62D /* Yahoo GBPUSD.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -811,9 +688,6 @@ files = ( ); inputPaths = ( - "$(SRCROOT)/Carthage/Build/iOS/Result.framework", - "$(SRCROOT)/Carthage/Build/iOS/DVR.framework", - "$(SRCROOT)/Carthage/Build/iOS/SwiftyJSON.framework", "$(SRCROOT)/Carthage/Build/iOS/ValueCoding.framework", ); name = "Carthage Copy Frameworks"; @@ -829,8 +703,6 @@ files = ( ); inputPaths = ( - "$(SRCROOT)/Carthage/Build/tvOS/Result.framework", - "$(SRCROOT)/Carthage/Build/tvOS/SwiftyJSON.framework", "$(SRCROOT)/Carthage/Build/tvOS/ValueCoding.framework", ); name = "Carthage Copy Frameworks"; @@ -846,9 +718,6 @@ files = ( ); inputPaths = ( - "$(SRCROOT)/Carthage/Build/Mac/Result.framework", - "$(SRCROOT)/Carthage/Build/Mac/DVR.framework", - "$(SRCROOT)/Carthage/Build/Mac/SwiftyJSON.framework", "$(SRCROOT)/Carthage/Build/Mac/ValueCoding.framework", ); name = "Carthage Copy Frameworks"; @@ -874,10 +743,7 @@ 65DEE33D1BFA0F370043A718 /* Currency.swift in Sources */, 65DEE3611BFA0F370043A718 /* Money.swift in Sources */, 65DEE3391BFA0F370043A718 /* Autogenerated.swift in Sources */, - 65DEE3551BFA0F370043A718 /* FX.swift in Sources */, - 65DEE35D1BFA0F370043A718 /* Yahoo.swift in Sources */, 65DEE3511BFA0F370043A718 /* Bitcoin.swift in Sources */, - 65DEE3591BFA0F370043A718 /* OpenExchangeRates.swift in Sources */, 65DEE3351BFA0F370043A718 /* ApplePay.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -887,13 +753,10 @@ buildActionMask = 2147483647; files = ( 65DD22BE1BFA10F30054F62D /* BitcoinTests.swift in Sources */, - 65DD22C11BFA10F30054F62D /* FXTests.swift in Sources */, 65DD22C51BFA10F30054F62D /* NSDecimalTests.swift in Sources */, 65DD22C31BFA10F30054F62D /* MoneyTests.swift in Sources */, 65579F8C1C01F0C100C3F8C7 /* DecimalNumberTypeTests.swift in Sources */, 65DD22C61BFA10F60054F62D /* ApplePayTests.swift in Sources */, - 65DD22C01BFA10F30054F62D /* FXOpenExchangeRatesTests.swift in Sources */, - 65DD22C21BFA10F30054F62D /* FXYahooTests.swift in Sources */, 65DD22C41BFA10F30054F62D /* NSDecimalNumberTests.swift in Sources */, 65DD22BF1BFA10F30054F62D /* DecimalTests.swift in Sources */, 65579FC61C0288A300C3F8C7 /* AutogeneratedTests.swift in Sources */, @@ -914,10 +777,7 @@ 65DEE3621BFA0F370043A718 /* Money.swift in Sources */, 65579FB71C0228EB00C3F8C7 /* Locale.swift in Sources */, 65DEE33A1BFA0F370043A718 /* Autogenerated.swift in Sources */, - 65DEE3561BFA0F370043A718 /* FX.swift in Sources */, - 65DEE35E1BFA0F370043A718 /* Yahoo.swift in Sources */, 65DEE3521BFA0F370043A718 /* Bitcoin.swift in Sources */, - 65DEE35A1BFA0F370043A718 /* OpenExchangeRates.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -934,10 +794,7 @@ 65DEE3631BFA0F370043A718 /* Money.swift in Sources */, 65579FB81C0228EB00C3F8C7 /* Locale.swift in Sources */, 65DEE33B1BFA0F370043A718 /* Autogenerated.swift in Sources */, - 65DEE3571BFA0F370043A718 /* FX.swift in Sources */, - 65DEE35F1BFA0F370043A718 /* Yahoo.swift in Sources */, 65DEE3531BFA0F370043A718 /* Bitcoin.swift in Sources */, - 65DEE35B1BFA0F370043A718 /* OpenExchangeRates.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -947,11 +804,8 @@ files = ( 65579FC71C0288A300C3F8C7 /* AutogeneratedTests.swift in Sources */, 65DD22B61BFA10F20054F62D /* BitcoinTests.swift in Sources */, - 65DD22B91BFA10F20054F62D /* FXTests.swift in Sources */, 65DD22BD1BFA10F20054F62D /* NSDecimalTests.swift in Sources */, 65DD22BB1BFA10F20054F62D /* MoneyTests.swift in Sources */, - 65DD22B81BFA10F20054F62D /* FXOpenExchangeRatesTests.swift in Sources */, - 65DD22BA1BFA10F20054F62D /* FXYahooTests.swift in Sources */, 65DD22BC1BFA10F20054F62D /* NSDecimalNumberTests.swift in Sources */, 6553909E1C037A1A00610C6F /* LocaleTests.swift in Sources */, 65579F8D1C01F0C100C3F8C7 /* DecimalNumberTypeTests.swift in Sources */, @@ -972,10 +826,7 @@ 65DEE3641BFA0F370043A718 /* Money.swift in Sources */, 65579FB91C0228EB00C3F8C7 /* Locale.swift in Sources */, 65DEE33C1BFA0F370043A718 /* Autogenerated.swift in Sources */, - 65DEE3581BFA0F370043A718 /* FX.swift in Sources */, - 65DEE3601BFA0F370043A718 /* Yahoo.swift in Sources */, 65DEE3541BFA0F370043A718 /* Bitcoin.swift in Sources */, - 65DEE35C1BFA0F370043A718 /* OpenExchangeRates.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -988,9 +839,6 @@ 65DD22B41BFA10F10054F62D /* NSDecimalNumberTests.swift in Sources */, 65DD22AF1BFA10F10054F62D /* DecimalTests.swift in Sources */, 65DD22B31BFA10F10054F62D /* MoneyTests.swift in Sources */, - 65DD22B11BFA10F10054F62D /* FXTests.swift in Sources */, - 65DD22B21BFA10F10054F62D /* FXYahooTests.swift in Sources */, - 65DD22B01BFA10F10054F62D /* FXOpenExchangeRatesTests.swift in Sources */, 6553909F1C037A1A00610C6F /* LocaleTests.swift in Sources */, 65579F8E1C01F0C100C3F8C7 /* DecimalNumberTypeTests.swift in Sources */, 65DD22AE1BFA10F10054F62D /* BitcoinTests.swift in Sources */, @@ -1055,12 +903,16 @@ 65B92ACC1BE0E46C00F82024 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ENABLE_TESTABILITY = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + ONLY_ACTIVE_ARCH = YES; }; name = Debug; }; 65B92ACD1BE0E46C00F82024 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + IPHONEOS_DEPLOYMENT_TARGET = 8.0; }; name = Release; }; diff --git a/Money.xcodeproj/xcshareddata/xcschemes/Money-OSX.xcscheme b/Money.xcodeproj/xcshareddata/xcschemes/Money-OSX.xcscheme index 79f3185..6c05b43 100644 --- a/Money.xcodeproj/xcshareddata/xcschemes/Money-OSX.xcscheme +++ b/Money.xcodeproj/xcshareddata/xcschemes/Money-OSX.xcscheme @@ -1,6 +1,6 @@ public typealias BTC = _Money -// MARK - cex.io FX - -/** - CEX.io Supported fiat currencies - - CEX only supports USD, EUR and RUB. - - - see: https://cex.io -*/ -public protocol CEXSupportedFiatCurrencyType: ISOCurrencyType { - - /** - CEX.io charge a percentage based commission with FX transactions. - - returns: a BankersDecimal representing the % commission. - */ - static var cex_commissionPercentage: BankersDecimal { get } -} - -extension Currency.USD: CEXSupportedFiatCurrencyType { - - /// - returns: the commission charged for USD transactions, a BankersDecimal - public static let cex_commissionPercentage: BankersDecimal = 0.2 -} - -extension Currency.EUR: CEXSupportedFiatCurrencyType { - - /// - returns: the commission charged for EUR transactions, a BankersDecimal - public static let cex_commissionPercentage: BankersDecimal = 0.2 -} - -extension Currency.RUB: CEXSupportedFiatCurrencyType { - - /// - returns: the commission charged for RUB transactions, a BankersDecimal - public static let cex_commissionPercentage: BankersDecimal = 0 -} - -struct _CEXBuy: CryptoCurrencyMarketTransactionType { - typealias BaseMoney = Base - typealias CounterMoney = BTC - typealias FiatCurrency = Base.Currency - static var transactionKind: CurrencyMarketTransactionKind { return .Buy } -} - -struct _CEXSell: CryptoCurrencyMarketTransactionType { - typealias BaseMoney = BTC - typealias CounterMoney = Counter - typealias FiatCurrency = Counter.Currency - static var transactionKind: CurrencyMarketTransactionKind { return .Sell } -} - -class _CEX: FXRemoteProvider, FXRemoteProviderType { - - static func name() -> String { - return "CEX.IO \(BaseMoney.Currency.code)\(CounterMoney.Currency.code)" - } - - static func request() -> NSURLRequest { - let url = NSURL(string: "https://cex.io/api/convert/\(BTC.Currency.code)/\(T.FiatCurrency.code)") - let request = NSMutableURLRequest(URL: url!) - request.HTTPMethod = "POST" - request.setValue("application/json", forHTTPHeaderField: "Content-Type") - let data = try! JSON(["amnt": Double(1.0)]).rawData() - request.HTTPBody = data - return request - } - - static func quoteFromNetworkResult(result: Result<(NSData?, NSURLResponse?), NSError>) -> Result { - return result.analysis( - - ifSuccess: { data, response in - - guard let data = data else { - return Result(error: .NoData) - } - - let json = JSON(data: data) - - if json.isEmpty { - return Result(error: .InvalidData(data)) - } - - guard let rateLiteral = json["amnt"].double else { - return Result(error: .RateNotFound(name())) - } - - let rate: BankersDecimal - - switch T.transactionKind { - case .Buy: - rate = BankersDecimal(floatLiteral: rateLiteral).reciprocal - case .Sell: - rate = BankersDecimal(floatLiteral: rateLiteral) - } - - return Result(value: FXQuote(rate: rate, percentage: T.FiatCurrency.cex_commissionPercentage)) - }, - - ifFailure: { error in - return Result(error: .NetworkError(error)) - } - ) - } -} - -/** - Represents the purchase of bitcoin using CEX.io. - - Usage is entirely type based - there is nothing to initialize. It is - generic over USD, EUR or RUB, no other currency types. For example. - - ```swift - CEXBuy.quote(1_000) { transaction in - // etc. - } - ``` - - The above sample represents buying US$1,000 worth of BTC using CEX.io. -*/ -public final class CEXBuy: _CEX<_CEXBuy> { } - - /** - Represents the sale of bitcoin using CEX.io. - - Usage is entirely type based - there is nothing to initialize. It is - generic over USD, EUR or RUB, no other currency types. For example. - - ```swift - CEXBuy.quote(10) { transaction in - // etc. - } - ``` - - The above sample represents selling 10 bitcoins for euros using CEX.io. - */ -public final class CEXSell: _CEX<_CEXSell> { } - - - - - diff --git a/Money/Shared/FX/FX.swift b/Money/Shared/FX/FX.swift deleted file mode 100644 index 54bf23c..0000000 --- a/Money/Shared/FX/FX.swift +++ /dev/null @@ -1,516 +0,0 @@ -// -// FX.swift -// Money -// -// The MIT License (MIT) -// -// Copyright (c) 2015 Daniel Thorpe -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - - -import Foundation -import ValueCoding -import Result -import SwiftyJSON - -/** - # MoneyPairType - Used to represent currency pairs. - - - see: [Wikipedia](https://en.wikipedia.org/wiki/Currency_pair) - */ -public protocol MoneyPairType { - - /// The currency which the quote is in relation to. - typealias BaseMoney: MoneyType - - /// The currency which is being traded/quoted - typealias CounterMoney: MoneyType -} - -/** - An enum to define the transaction from the perspective - of the user. i.e. either a buy or sell. -*/ -public enum CurrencyMarketTransactionKind { - /// User is performing a buy transaction - case Buy - /// User is performing a sell transaction - case Sell -} - -/** - A protocol to define a currency market transaction. It refines - MoneyPairType. It exposes the kind of transaction as a property. -*/ -public protocol CurrencyMarketTransactionType: MoneyPairType { - - /// - returns: the transactionKind, a CurrencyMarketTransactionKind - static var transactionKind: CurrencyMarketTransactionKind { get } -} - -/** - A protocol to define a crypto currency market transaction. It refines - CurrencyMarketTransactionType, and adds a new typealias for the FiatCurrency. - - By crypto currency market transaction, we refer to a currency exchange - involving a crypto currency, such as bitcoin, or litecoin or similar. - - A Fiat Currency is a currency which is maintained by a national bank, such as - USD, or EUR. - - Typrically a crypto currency market transaction is where the user is purchasing - bitcoin with USD, or selling bitcoin for USD. -*/ -public protocol CryptoCurrencyMarketTransactionType: CurrencyMarketTransactionType { - typealias FiatCurrency: ISOCurrencyType -} - -/** - # Quote - Represents an FX quote with a rate and commision - percentage. By default the percentage is 0. -*/ -public struct FXQuote: ValueCoding { - - /// The Coder required for ValueCoding - public typealias Coder = FXQuoteCoder - - /// The exchange rate, stored as a `BankersDecimal`. - public let rate: BankersDecimal - - /// The commission as a percentage, e.g. 0.2 => 0.2% - public let percentage: BankersDecimal - - /** - Construct with a rate and commission percentage (defaults to - zero). - - - parameter rate: a `BankersDecimal`. - - parameter percentage: a `BankersDecimal`. - - returns: a `FXQuote` - */ - public init(rate: BankersDecimal, percentage: BankersDecimal = 0) { - self.rate = rate - self.percentage = percentage - } - - /** - ## Calculate the commission. - Taken as the ammount of the base currency. - */ - public func commission(base: B) -> B { - return (percentage / 100) * base - } - - /** - ## Calculate transaction value - Lets assume we want to convert EUR 100 in to USD. The - quote type has the rate of EUR/USD stored in a - bankers decimal. The framework will effectively do - something like this: - - let eur: EUR = 100 - let usd: USD = rate.transactionValueForBaseValue(eur) - - Most foreign exchange services will build their commission - into their rates. So to implement a provider for a serivce - can work just like the `Yahoo` one here. - */ - public func transactionValueForBaseValue(base: B) -> C { - return ((1 - (percentage / 100)) * base).convertWithRate(rate) - } -} - -/** - FXTransaction is a generic value type which represents a - foreign currency transaction. It is generic over two - MoneyType. - - There are some restrictions on the two generic types, to support - the mathematics and ValueCoding. However, essentially, if you use - _Money then these are limitations are all met. - - - see: MoneyPairType -*/ -public struct FXTransaction: MoneyPairType, ValueCoding { - - public typealias Coder = FXTransactionCoder - public typealias BaseMoney = Base - public typealias CounterMoney = Counter - - /// - returns: the BaseMoney value. - public let base: BaseMoney - - /// - returns: the BaseMoney commission. - public let commission: BaseMoney - - /// - returns: the rate, a BankersDecimal. - public let rate: BankersDecimal - - /// - returns: the CounterMoney value. - public let counter: CounterMoney - - internal init(base: BaseMoney, commission: BaseMoney, rate: BankersDecimal, counter: CounterMoney) { - self.base = base - self.commission = commission - self.rate = rate - self.counter = counter - } - - /** - A FXTransaction can be created with the BaseMoney value (i.e. how much money - is being exchanged), and the FXQuote value. Using the quote, the - counter value (i.e. how much is received) and commission (i.e. how much of - the base is spent on commission) is automatically calculated. - - - parameter base: the value for base - - parameter quote: a FXQuote - - returns: an initialized FXTransaction value - */ - public init(base: BaseMoney, quote: FXQuote) { - self.base = base - self.commission = quote.commission(base) - self.rate = quote.rate - self.counter = quote.transactionValueForBaseValue(base) - } -} - -/** - # FXError - This is an error type used in FX methods. -*/ -public enum FXError: ErrorType, Equatable { - - /// When there is a network error - case NetworkError(NSError) - - /// If there was no data/response - case NoData - - /// If the data was corrupted or invalid - case InvalidData(NSData) - - /// If a rate could not be found - case RateNotFound(String) -} - -/** - # FX Provider - `FXProviderType` defines the interface for a FX - provider. - - `FXProviderType` refines `CurrencyPairType` which - means that FX Providers should be generic types. E.g. - - AcmeFX - - would be the provider type, to exchange EUR to USD - using AcmeFX services. -*/ -public protocol FXProviderType: MoneyPairType { - - /// The name of the provider. - static func name() -> String -} - -// MARK: - Protocol: Local Provider - -/** - # FX Local Provider - `FXLocalProvider` defines an interface for a FX service - which stores its rates locally, and can make synchronous - exchanges. - - A typical usage for this would be when converting between - your applications custom currencies, for example in a game. -*/ -public protocol FXLocalProviderType: FXProviderType { - - /** - Generate the quote using the `BaseMoney` and - `CounterMoney` generic types. - - - returns: a `FXQuote` which contains the rate. - */ - static func quote() -> FXQuote -} - -extension FXLocalProviderType where - BaseMoney.Coder: NSCoding, - BaseMoney.Coder.ValueType == BaseMoney, - BaseMoney.DecimalStorageType == BankersDecimal.DecimalStorageType, - CounterMoney.Coder: NSCoding, - CounterMoney.Coder.ValueType == CounterMoney, - CounterMoney.DecimalStorageType == BankersDecimal.DecimalStorageType { - - public typealias Transaction = FXTransaction - - /** - This is the primary API used to determine for Foreign Exchange transactions. - */ - public static func fx(base: BaseMoney) -> Transaction { - return Transaction(base: base, quote: quote()) - } -} - -/** - FX Providers which get their rates via a network request - should conform to `FXRemoteProviderType`, which defines - how the network request should be made. -*/ -public protocol FXRemoteProviderType: FXProviderType { - - /** - Return the NSURLSession to use to make the request. It - should be notes that this session must be retained by - something in memory, e.g. use a shared session, or - a session owned by a singleton. - - By default, returns `NSURLSession.sharedSession()`. - - - returns: a `NSURLSession`. - */ - static func session() -> NSURLSession - - /** - Create a suitable NSURLRequest to convert from the - base currency code to the target currency code. - - Typically, these will just be contatanted together - to form a ticker, however, some providers may use - query paramters. - - - parameter base: the currency code of the base currency, a `String` - - parameter symbol: the currency code of the target currency, a `String` - - returns: a `NSURLRequest` - */ - static func request() -> NSURLRequest - - /** - Parse the received NSData into the providers own QuoteType. More - than likely, this will just be `FXQuote`, but providers may - support fees/commission info which needs representing. - - - parameter data: the `NSData` received from the service provider - - returns: a `Result` generic over the `QuoteType` and `FX.Error` which - supports general errors for mal-formed or missing information. - */ - static func quoteFromNetworkResult(result: Result<(NSData?, NSURLResponse?), NSError>) -> Result -} - -extension FXRemoteProviderType { - - /** - Default implementation to return the shared - `NSURLSession`. - */ - public static func session() -> NSURLSession { - return NSURLSession.sharedSession() - } -} - -extension FXRemoteProviderType where - BaseMoney.Coder: NSCoding, - BaseMoney.Coder.ValueType == BaseMoney, - BaseMoney.DecimalStorageType == BankersDecimal.DecimalStorageType, - CounterMoney.Coder: NSCoding, - CounterMoney.Coder.ValueType == CounterMoney, - CounterMoney.DecimalStorageType == BankersDecimal.DecimalStorageType { - - public typealias Transaction = FXTransaction - - internal static func fxFromQuoteWithBase(base: BaseMoney) -> FXQuote -> Transaction { - return { Transaction(base: base, quote: $0) } - } - - /** - # 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)") - } - - - 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 -> 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 { - return quote(base) { completion($0.map { $0.counter }) } - } -} - -internal class FXServiceProviderNetworkClient { - let session: NSURLSession - - init(session: NSURLSession = NSURLSession.sharedSession()) { - self.session = session - } - - func get(request: NSURLRequest, adaptor: Result<(NSData?, NSURLResponse?), NSError> -> Result, completion: Result -> Void) -> NSURLSessionDataTask { - let task = session.dataTaskWithRequest(request) { data, response, error in - let result = error.map { Result(error: $0) } ?? Result(value: (data, response)) - completion(adaptor(result)) - } - task.resume() - return task - } -} - -/** - A trivial generic class suitable for subclassing for FX remote providers. - It automatically sets up the typealias for MoneyPairType. -*/ -public class FXRemoteProvider { - public typealias BaseMoney = B - public typealias CounterMoney = T -} - -// MARK: - ValueCoding - -/** - A CodingType which codes FXQuote -*/ -public final class FXQuoteCoder: NSObject, NSCoding, CodingType { - enum Keys: String { - case Rate = "rate" - case Percentage = "percentage" - } - - /// The value being encoded or decoded - public let value: FXQuote - - /// Initialized with an FXQuote - public required init(_ v: FXQuote) { - value = v - } - - public init?(coder aDecoder: NSCoder) { - let rate = BankersDecimal.decode(aDecoder.decodeObjectForKey(Keys.Rate.rawValue)) - let percentage = BankersDecimal.decode(aDecoder.decodeObjectForKey(Keys.Percentage.rawValue)) - value = FXQuote(rate: rate!, percentage: percentage!) - } - - public func encodeWithCoder(aCoder: NSCoder) { - aCoder.encodeObject(value.rate.encoded, forKey: Keys.Rate.rawValue) - aCoder.encodeObject(value.percentage.encoded, forKey: Keys.Percentage.rawValue) - } -} - - -private enum FXTransactionCoderKeys: String { - case Base = "base" - case Commission = "commission" - case Rate = "rate" - case Counter = "counter" -} - -/** - A CodingType which codes FXTransaction -*/ -public final class FXTransactionCoder: NSObject, NSCoding, CodingType { - - /// The value being encoded or decoded - public let value: FXTransaction - - /// Initialized with an FXTransaction - public required init(_ v: FXTransaction) { - value = v - } - - public init?(coder aDecoder: NSCoder) { - let base: Base? = Base.decode(aDecoder.decodeObjectForKey(FXTransactionCoderKeys.Base.rawValue)) - let rate = BankersDecimal.decode(aDecoder.decodeObjectForKey(FXTransactionCoderKeys.Rate.rawValue)) - let commission = Base.decode(aDecoder.decodeObjectForKey(FXTransactionCoderKeys.Commission.rawValue)) - let counter = Counter.decode(aDecoder.decodeObjectForKey(FXTransactionCoderKeys.Counter.rawValue)) - value = FXTransaction(base: base!, commission: commission!, rate: rate!, counter: counter!) - } - - public func encodeWithCoder(aCoder: NSCoder) { - aCoder.encodeObject(value.base.encoded, forKey: FXTransactionCoderKeys.Base.rawValue) - aCoder.encodeObject(value.rate.encoded, forKey: FXTransactionCoderKeys.Rate.rawValue) - aCoder.encodeObject(value.commission.encoded, forKey: FXTransactionCoderKeys.Commission.rawValue) - aCoder.encodeObject(value.counter.encoded, forKey: FXTransactionCoderKeys.Counter.rawValue) - } -} - - -public func ==(lhs: FXError, rhs: FXError) -> Bool { - switch (lhs, rhs) { - case let (.NetworkError(aError), .NetworkError(bError)): - return aError.isEqual(bError) - case (.NoData, .NoData): - return true - case let (.InvalidData(aData), .InvalidData(bData)): - return aData.isEqualToData(bData) - case let (.RateNotFound(aStr), .RateNotFound(bStr)): - return aStr == bStr - default: - return false - } -} - diff --git a/Money/Shared/FX/OpenExchangeRates.swift b/Money/Shared/FX/OpenExchangeRates.swift deleted file mode 100644 index 5a963ed..0000000 --- a/Money/Shared/FX/OpenExchangeRates.swift +++ /dev/null @@ -1,157 +0,0 @@ -// -// OpenExchangeRates.swift -// Money -// -// The MIT License (MIT) -// -// Copyright (c) 2015 Daniel Thorpe -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import Foundation -import ValueCoding -import Result -import SwiftyJSON - - -// MARK: - Open Exchange Rates FX Service Provider - -/** -# Open Exchange Rates -Open Exchange Rates (OER) is a popular FX provider, -which does have a "forever free" service, which will -only return rates for all supported currencies with -USD as the base currency. - -Paid for access allows specification of the base & -counter currency. - -All access requires an "app_id", even the forever -free one. - -This protocol defines a type which can return the -app_id. Therefore, consumers should define their -own type which conforms, and then using whatever -mechanism you want, return your OER app_id. I -recommend using something like [CocoaPod Keys](https://github.com/orta/cocoapods-keys) - -Lets say, you create this... - - -struct MyOpenExchangeRatesAppID: OpenExchangeRatesAppID { -static let app_id = "blarblarblarblar" -} - -Now, create subclasses of `_OpenExchangeRates` or -`_ForeverFreeOpenExchangeRates` depending on your access level. - -e.g. If you have a forever free app_id: - - -class OpenExchangeRates: _ForeverFreeOpenExchangeRates { } - -usage would then be like this: - - -let usd: USD = 100 -OpenExchangeRates.fx(usd) { result in -// etc, result will include the GBP exchanged for US$ 100 -} - -If you have paid for access to OpenExchangeRates then instead -create the following subclass: - - -class OpenExchangeRates: _OpenExchangeRates { } - -- see: [https://openexchangerates.org](https://openexchangerates.org) -- see: [CocoaPod Keys](https://github.com/orta/cocoapods-keys) - -*/ -public protocol OpenExchangeRatesAppID { - static var app_id: String { get } -} - -/** - # Open Exchange Rates - Base class for OpenExchangeRates.org. See the docs above. - - - see: `OpenExchangeRatesAppID` - */ -public class _OpenExchangeRates: FXRemoteProvider, FXRemoteProviderType { - - public static func name() -> String { - return "OpenExchangeRates.org \(Base.Currency.code)\(Counter.Currency.code)" - } - - public static func request() -> NSURLRequest { - var url = NSURL(string: "https://openexchangerates.org/api/latest.json?app_id=\(ID.app_id)")! - - switch BaseMoney.Currency.code { - case Currency.USD.code: - break - default: - url = url.URLByAppendingPathComponent("&base=\(BaseMoney.Currency.code)") - } - - return NSURLRequest(URL: url) - } - - public static func quoteFromNetworkResult(result: Result<(NSData?, NSURLResponse?), NSError>) -> Result { - return result.analysis( - - ifSuccess: { data, response in - - guard let data = data else { - return Result(error: .NoData) - } - - let json = JSON(data: data) - - if json.isEmpty { - return Result(error: .InvalidData(data)) - } - - guard let rate = json[["rates", CounterMoney.Currency.code]].double else { - return Result(error: .RateNotFound(name())) - } - - return Result(value: FXQuote(rate: BankersDecimal(floatLiteral: rate))) - }, - - ifFailure: { error in - return Result(error: .NetworkError(error)) - } - ) - } -} - -/** - # Open Exchange Rates - Forever Free class for OpenExchangeRates.org. See the docs above. - - - see: `OpenExchangeRatesAppID` - */ -public class _ForeverFreeOpenExchangeRates: _OpenExchangeRates { } - - - - - - diff --git a/Money/Shared/FX/Yahoo.swift b/Money/Shared/FX/Yahoo.swift deleted file mode 100644 index c3eacb6..0000000 --- a/Money/Shared/FX/Yahoo.swift +++ /dev/null @@ -1,107 +0,0 @@ -// -// Yahoo.swift -// Money -// -// The MIT License (MIT) -// -// Copyright (c) 2015 Daniel Thorpe -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import Foundation -import ValueCoding -import Result -import SwiftyJSON - - -// MARK: - Yahoo FX Service Provider - -/** -# Yahoo FX -This type uses Yahoo's Currency Converter. E.g. - -It is generic over two `MoneyType`s, and is only -used as a type - there is no initializer. - -```swift -Yahoo.fx(100) { jpy in -print("\(jpy)") // is a Result -} -``` - -*/ -public final class Yahoo: FXRemoteProvider, FXRemoteProviderType { - - /** - Access the name of the FX provider (e.g. "Yahoo USDEUR") - - - returns: a `String`. - */ - public static func name() -> String { - return "Yahoo \(Base.Currency.code)\(Counter.Currency.code)" - } - - /** - Constructs the `NSURLRequest` to Yahoo's currency convertor service. - - - returns: a `NSURLRequest`. - */ - public static func request() -> NSURLRequest { - return NSURLRequest(URL: NSURL(string: "https://download.finance.yahoo.com/d/quotes.csv?s=\(BaseMoney.Currency.code)\(CounterMoney.Currency.code)=X&f=nl1")!) - } - - /** - This function is used to map the network result into a quote. - - - paramter result: the network result, represented as `Result` where - the value, T, is a tuple of data and response. The error, E, is an `NSError`. - - returns: a `Result`. - */ - public static func quoteFromNetworkResult(result: Result<(NSData?, NSURLResponse?), NSError>) -> Result { - return result.analysis( - - ifSuccess: { data, response in - - guard let data = data else { - return Result(error: .NoData) - } - - guard let str = String(data: data, encoding: NSUTF8StringEncoding) else { - return Result(error: .InvalidData(data)) - } - - let components = str.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()).componentsSeparatedByString(",") - - if components.count < 2 { - return Result(error: .InvalidData(data)) - } - - guard let rate = Double(components[1]) else { - return Result(error: .RateNotFound(str)) - } - - return Result(value: FXQuote(rate: BankersDecimal(floatLiteral: rate))) - }, - - ifFailure: { error in - return Result(error: .NetworkError(error)) - } - ) - } -} diff --git a/README.md b/README.md index 009eae1..3a3231c 100644 --- a/README.md +++ b/README.md @@ -162,79 +162,6 @@ The convenience initializer receives an array of `PaymentSummaryItem` values and `PaymentSummaryItem` conforms to `Hashable` and [`ValueCoding`](https://github.com/danthorpe/ValueCoding). -## 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 too. - -The following code snippet represents a currency exchange using Yahoo’s currency converter. - -```swift -Yahoo.quote(100) { result in - if let tx = result.value { - print("Exchanged \(tx.base) into \(tx.counter) with a rate of \(tx.rate) and \(tx.commission) commission.") - } -} -``` - -> Exchanged US$ 100.00 into € 93.09 with a rate of 0.93089 and US$ 0.00 commission. - -The result, delivered asynchronously, uses [`Result`](http://github.com/antitypical/Result) to encapsulate either a `FXTransaction` or an `FXError` value. Obviously, in real code - you’d need to check for errors ;) - -`FXTransaction` is a generic type which composes the base and counter monies, the rate of the exchange, and any commission the FX service provider charged in the base currency. Currently `FXQuote` only supports percentage based commission. - -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(€ 93.09) - -### Creating custom FX service providers - -Creating a custom FX service provider is straightforward. The protocols `FXLocalProviderType` and `FXRemoteProviderType` define the minimum requirements. The `quote` and `fx` methods are provided via extensions on the protocols. - -For a remote FX service provider, i.e. one which will make a network request to get a rate, we can look at the `Yahoo` provider to see how it works. - -Firstly, we subclass the generic class `FXRemoteProvider`. The generic types are both constrained to `MoneyType`. The naming conventions follow those of a [currency pair](https://en.wikipedia.org/wiki/Currency_pair). - -```swift -public class Yahoo: FXRemoteProvider, FXRemoteProviderType { - // etc -} -``` - -`FXRemoteProvider` provides the typealiases for `BaseMoney` and `CounterMoney` which will be needed to introspect the currency codes. - -The protocol requires that we can construct a `NSURLRequest`. - -```swift -public static func request() -> NSURLRequest { - return NSURLRequest(URL: NSURL(string: "https://download.finance.yahoo.com/d/quotes.csv?s=\(BaseMoney.Currency.code)\(CounterMoney.Currency.code)=X&f=nl1")!) -} -``` - -The last requirement, is that the network result can be mapped into a `Result`. - -`FXQuote` is a struct, which composes the exchange rate and percentage commission to be used. Both properties are `BankersDecimal` values (see below on the decimal implementation details). - -```swift -public static func quoteFromNetworkResult(result: Result<(NSData?, NSURLResponse?), NSError>) -> Result { - return result.analysis( - ifSuccess: { data, response in - let rate: BankersDecimal = 1.5 // or whatever - return Result(value: FXQuote(rate: rate)) - }, - ifFailure: { error in - return Result(error: .NetworkError(error)) - } - ) -} -``` - -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. - ## Bitcoin Money has support for Bitcoin types, the popular `BTC` and the unofficial ISO 4217 currency code `XBT`. @@ -249,38 +176,9 @@ print(“You have \(bitcoin)”) ``` > You have Ƀ0.12345678 -Money has support for using [CEX.IO](https://cex.io)’s [trade api](https://cex.io/api) to support quotes of Bitcoin currency exchanges. CEX only supports `USD`, `EUR,` and `RUB` [fiat currencies](https://en.wikipedia.org/wiki/Fiat_money). +## Foreign Exchange (FX) -It’s usage is a little bit different for a regular FX. To represent the purchase of Bitcoins use `CEXBuy` like this: - -```swift -CEXBuy.quote(100) { result in - if let tx = result.value { - print("\(tx.base) will buy \(tx.counter) at a rate of \(tx.rate) with \(tx.commission)") - } -} -``` -> US$ 100.00 will buy Ƀ0.26219275 at a rate of 0.0026272 with US$ 0.20 commission. - -To represent the sale of Bitcoins use `CEXSell` like this: - -```swift -CEXSell.quote(50) { result in - if let tx = result.value { - print("\(tx.base) will sell for \(tx.counter) at a rate of \(tx.rate) with \(tx.commission) commission.") - } -} -``` -> Ƀ50.00 will sell for € 17,541.87 at a rate of 351.5405 with Ƀ0.10 commission. - -If trying to buy or sell using a currency not supported by CEX the compiler will prevent your code from compiling. - -```swift -CEXSell.quote(50) { result in - // etc -} -``` -> Type 'Currency.GBP' does not conform to protocol 'CEXSupportedFiatCurrencyType' +The FX support which was previously part of this framework has been moved into its own, called [FX](https://github.com/danthorpe/FX). # Creating custom currencies diff --git a/Supporting Files/Money.xcconfig b/Supporting Files/Money.xcconfig index 71d18b0..7c0150b 100644 --- a/Supporting Files/Money.xcconfig +++ b/Supporting Files/Money.xcconfig @@ -6,7 +6,7 @@ // // -MONEY_VERSION = 1.4.2 +MONEY_VERSION = 1.5.0 APPLICATION_EXTENSION_API_ONLY = YES INFOPLIST_FILE = $(SRCROOT)/Supporting Files/Info.plist diff --git a/Tests/Shared/BitcoinTests.swift b/Tests/Shared/BitcoinTests.swift index 60324f0..c49696b 100644 --- a/Tests/Shared/BitcoinTests.swift +++ b/Tests/Shared/BitcoinTests.swift @@ -7,9 +7,6 @@ // import XCTest -import Result -import DVR -import SwiftyJSON @testable import Money @@ -32,184 +29,3 @@ class BitcoinCurrencyTests: XCTestCase { } } -class CEXTests: XCTestCase { - - func test__usd_commission_percentage() { - XCTAssertEqual(Currency.USD.cex_commissionPercentage, 0.2) - } - - func test__eur_commission_percentage() { - XCTAssertEqual(Currency.EUR.cex_commissionPercentage, 0.2) - } - - func test__rub_commission_percentage() { - XCTAssertEqual(Currency.RUB.cex_commissionPercentage, 0) - } -} - -class FXCEXBuyTests: FXProviderTests { - - typealias Provider = CEXBuy - typealias TestableProvider = TestableFXRemoteProvider - typealias FaultyProvider = FaultyFXRemoteProvider - - func test__name() { - XCTAssertEqual(Provider.name(), "CEX.IO USDBTC") - } - - func test__session() { - XCTAssertEqual(Provider.session(), NSURLSession.sharedSession()) - } - - func test__quote_adaptor__with_network_error() { - let error = NSError(domain: NSURLErrorDomain, code: NSURLError.BadServerResponse.rawValue, userInfo: nil) - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(error: error) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.NetworkError(error)) - } - - func test__quote_adaptor__with_no_data() { - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(value: (.None, .None)) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.NoData) - } - - func test__quote_adaptor__with_garbage_data() { - let data = createGarbageData() - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(value: (data, .None)) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.InvalidData(data)) - } - - func test__quote_adaptor__with_missing_rate() { - let json = dvrJSONFromCassette(Provider.name())! - var dic = json.dictionaryValue - dic["amount"] = json["amnt"] - dic.removeValueForKey("amnt") - let data = try! JSON(dic).rawData() - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(value: (data, .None)) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.RateNotFound(Provider.name())) - } - - func test__faulty_provider() { - let expectation = expectationWithDescription("Test: \(__FUNCTION__)") - - FaultyProvider.fx(100) { result in - guard let error = result.error else { - XCTFail("Should have received a network error.") - return - } - switch error { - case .NetworkError(_): - break // This is the success path. - default: - XCTFail("Returned \(error), should be a .NetworkError") - } - expectation.fulfill() - } - - waitForExpectationsWithTimeout(1, handler: nil) - } - - func test__fx() { - let expectation = expectationWithDescription("Test: \(__FUNCTION__)") - - TestableProvider.fx(100) { result in - if let usd = result.value { - XCTAssertEqual(usd, 0.25470294) - } - else { - XCTFail("Received error: \(result.error!).") - } - expectation.fulfill() - } - - waitForExpectationsWithTimeout(1, handler: nil) - } - -} - -class FXCEXSellTests: FXProviderTests { - - typealias Provider = CEXSell - typealias TestableProvider = TestableFXRemoteProvider - typealias FaultyProvider = FaultyFXRemoteProvider - - func test__name() { - XCTAssertEqual(Provider.name(), "CEX.IO BTCUSD") - } - - func test__session() { - XCTAssertEqual(Provider.session(), NSURLSession.sharedSession()) - } - - func test__quote_adaptor__with_network_error() { - let error = NSError(domain: NSURLErrorDomain, code: NSURLError.BadServerResponse.rawValue, userInfo: nil) - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(error: error) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.NetworkError(error)) - } - - func test__quote_adaptor__with_no_data() { - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(value: (.None, .None)) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.NoData) - } - - func test__quote_adaptor__with_garbage_data() { - let data = createGarbageData() - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(value: (data, .None)) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.InvalidData(data)) - } - - func test__quote_adaptor__with_missing_rate() { - let json = dvrJSONFromCassette(Provider.name())! - var dic = json.dictionaryValue - dic["amount"] = json["amnt"] - dic.removeValueForKey("amnt") - let data = try! JSON(dic).rawData() - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(value: (data, .None)) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.RateNotFound(Provider.name())) - } - - func test__faulty_provider() { - let expectation = expectationWithDescription("Test: \(__FUNCTION__)") - - FaultyProvider.fx(100) { result in - guard let error = result.error else { - XCTFail("Should have received a network error.") - return - } - switch error { - case .NetworkError(_): - break // This is the success path. - default: - XCTFail("Returned \(error), should be a .NetworkError") - } - expectation.fulfill() - } - - waitForExpectationsWithTimeout(1, handler: nil) - } - - func test__fx() { - let expectation = expectationWithDescription("Test: \(__FUNCTION__)") - - TestableProvider.fx(100) { result in - if let btc = result.value { - XCTAssertEqual(btc, 39_198.35) - } - else { - XCTFail("Received error: \(result.error!).") - } - expectation.fulfill() - } - - waitForExpectationsWithTimeout(1, handler: nil) -} - -} - diff --git a/Tests/Shared/DVR Cassettes/CEX.IO BTCUSD.json b/Tests/Shared/DVR Cassettes/CEX.IO BTCUSD.json deleted file mode 100644 index a21a649..0000000 --- a/Tests/Shared/DVR Cassettes/CEX.IO BTCUSD.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "interactions" : [ - { - "recorded_at" : 1447005471.048528, - "response" : { - "body" : "{\"amnt\":392.769}", - "status" : 200, - "url" : "https:\/\/cex.io\/api\/convert\/BTC\/USD", - "headers" : { - "cf-ray" : "242329a0c16434fa-LHR", - "Content-Type" : "text\/json", - "Server" : "cloudflare-nginx", - "Set-Cookie" : "__cfduid=d8814e674eaa6d74dc7111b40e1725e7b1447005470; expires=Mon, 07-Nov-16 17:57:50 GMT; path=\/; domain=.cex.io; HttpOnly, cex-prod-session=s%3A6IA4GuKmoXs-ScYlPBKxws7x.uy4t0GEq2h32KeFJtxSJqirGgP6s44E%2FLaOe%2FhN%2F4x0; Domain=.cex.io; Path=\/; HttpOnly; Secure", - "Vary" : "Accept-Encoding", - "Date" : "Sun, 08 Nov 2015 17:57:50 GMT", - "x-frame-options" : "DENY", - "Access-Control-Allow-Origin" : "*" - } - }, - "request" : { - "method" : "POST", - "body" : { - "amnt" : 1 - }, - "url" : "https:\/\/cex.io\/api\/convert\/BTC\/USD", - "headers" : { - "Content-Type" : "application\/json" - } - } - } - ], - "name" : "CEX.IO BTCUSD" -} diff --git a/Tests/Shared/DVR Cassettes/CEX.IO USDBTC.json b/Tests/Shared/DVR Cassettes/CEX.IO USDBTC.json deleted file mode 100644 index 53fdbe8..0000000 --- a/Tests/Shared/DVR Cassettes/CEX.IO USDBTC.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "interactions" : [ - { - "recorded_at" : 1447008110.14736, - "response" : { - "body" : "{\"amnt\":391.829}", - "status" : 200, - "url" : "https:\/\/cex.io\/api\/convert\/BTC\/USD", - "headers" : { - "cf-ray" : "24236a1032de359c-LHR", - "Content-Type" : "text\/json", - "Server" : "cloudflare-nginx", - "Set-Cookie" : "__cfduid=d0c2769b88e78f6e46f6c4c5fccb84c081447008110; expires=Mon, 07-Nov-16 18:41:50 GMT; path=\/; domain=.cex.io; HttpOnly, cex-prod-session=s%3AvnzWUOJ65E4m9XYY5vh_JvmJ.LwHdvFj55w6G%2Bxo1jkzIyyE6n0dY%2FiC6GXiqK4tlQgk; Domain=.cex.io; Path=\/; HttpOnly; Secure", - "Vary" : "Accept-Encoding", - "Date" : "Sun, 08 Nov 2015 18:41:50 GMT", - "x-frame-options" : "DENY", - "Access-Control-Allow-Origin" : "*" - } - }, - "request" : { - "method" : "POST", - "body" : { - "amnt" : 1 - }, - "url" : "https:\/\/cex.io\/api\/convert\/BTC\/USD", - "headers" : { - "Content-Type" : "application\/json" - } - } - } - ], - "name" : "CEX.IO USDBTC" -} diff --git a/Tests/Shared/DVR Cassettes/OpenExchangeRates.org USDEUR.json b/Tests/Shared/DVR Cassettes/OpenExchangeRates.org USDEUR.json deleted file mode 100644 index 1462f6f..0000000 --- a/Tests/Shared/DVR Cassettes/OpenExchangeRates.org USDEUR.json +++ /dev/null @@ -1,206 +0,0 @@ -{ - "interactions" : [ - { - "recorded_at" : 1446674543.534192, - "response" : { - "body" : { - "disclaimer" : "Exchange rates are provided for informational purposes only, and do not constitute financial advice of any kind. Although every attempt is made to ensure quality, NO guarantees are given whatsoever of accuracy, validity, availability, or fitness for any purpose - please use at your own risk. All usage is subject to your acceptance of the Terms and Conditions of Service, available at: https:\/\/openexchangerates.org\/terms\/", - "license" : "Data sourced from various providers with public-facing APIs; copyright may apply; resale is prohibited; no warranties given of any kind. Bitcoin data provided by http:\/\/coindesk.com. All usage is subject to your acceptance of the License Agreement available at: https:\/\/openexchangerates.org\/license\/", - "timestamp" : 1446670811, - "rates" : { - "HRK" : 6.955088, - "HUF" : 288.542199, - "CDF" : 928.03575, - "ILS" : 3.882166, - "NGN" : 199.0678, - "GYD" : 206.382169, - "BYR" : 17438.025, - "BHD" : 0.377283, - "SZL" : 13.94123, - "INR" : 65.55212, - "SDG" : 6.08656, - "PEN" : 3.289123, - "EUR" : 0.920924, - "QAR" : 3.639692, - "PGK" : 2.937225, - "LRD" : 86.08000199999999, - "ISK" : 129.402999, - "SYP" : 188.821003, - "TRY" : 2.857284, - "UAH" : 23.03988, - "SGD" : 1.402269, - "MMK" : 1276.425025, - "NIO" : 27.47016, - "BIF" : 1565.305, - "AFN" : 64.980002, - "LKR" : 141.369399, - "GTQ" : 7.656958, - "CHF" : 0.992761, - "XPT" : 0.001048, - "THB" : 35.54216, - "AMD" : 474.750003, - "AOA" : 135.254335, - "SEK" : 8.616823999999999, - "SAR" : 3.75026, - "KWD" : 0.303096, - "IRR" : 29961.5, - "WST" : 2.620993, - "BGN" : 1.797365, - "BMD" : 1, - "PHP" : 46.81726, - "XAF" : 602.598085, - "ZMW" : 12.600125, - "BDT" : 78.40590899999999, - "NOK" : 8.621670999999999, - "BOB" : 6.901134, - "TZS" : 2160.843317, - "BND" : 1.401763, - "VEF" : 6.321734, - "ANG" : 1.78875, - "EEK" : 14.324475, - "SCR" : 12.69805, - "VUV" : 112.092499, - "XAG" : 0.066279, - "KYD" : 0.824592, - "DJF" : 177.668751, - "XCD" : 2.70102, - "CLF" : 0.024602, - "LSL" : 13.929038, - "MOP" : 7.988528, - "ALL" : 127.199899, - "UZS" : 2692.314942, - "PLN" : 3.896384, - "UYU" : 29.36398, - "LTL" : 3.104616, - "LYD" : 1.354645, - "JPY" : 121.4192, - "MNT" : 1992.833333, - "FJD" : 2.145517, - "ZWL" : 322.387247, - "KPW" : 900.09, - "PKR" : 105.463701, - "MRO" : 322.4525, - "GBP" : 0.649952, - "MTL" : 0.683602, - "OMR" : 0.385079, - "LVL" : 0.635748, - "SHP" : 0.649952, - "GEL" : 2.396075, - "TND" : 2.012077, - "DKK" : 6.853054, - "KRW" : 1133.813338, - "NPR" : 105.1052, - "BSD" : 1, - "CRC" : 533.607406, - "EGP" : 8.029902, - "AUD" : 1.398273, - "BTC" : 0.002153611, - "MAD" : 9.89598, - "SLL" : 4500, - "MWK" : 573.4781, - "RSD" : 110.54824, - "NZD" : 1.518215, - "SRD" : 3.2875, - "CLP" : 691.710994, - "RUB" : 63.21985, - "HKD" : 7.750945, - "NAD" : 13.93873, - "GMD" : 39.06982, - "VND" : 22314.566667, - "LAK" : 8147.764903, - "CUC" : 1, - "RON" : 4.083066, - "MUR" : 35.896501, - "XAU" : 0.0009015, - "GGP" : 0.649952, - "BRL" : 3.806566, - "MXN" : 16.50496, - "STD" : 22368.55, - "AWG" : 1.793333, - "MVR" : 15.321917, - "PAB" : 1, - "TJS" : 6.6207, - "GNF" : 7948.197598, - "MGA" : 3260.923301, - "XDR" : 0.718687, - "ETB" : 21.04244, - "COP" : 2849.045036, - "ZAR" : 13.92742, - "IDR" : 13577.1, - "SVC" : 8.753053, - "CVE" : 101.54568486, - "TTD" : 6.367038, - "GIP" : 0.649952, - "PYG" : 5600.131693, - "MZN" : 43.6925, - "FKP" : 0.649952, - "KZT" : 285.87379, - "UGX" : 3490.123333, - "USD" : 1, - "ARS" : 9.55316, - "GHS" : 3.814842, - "RWF" : 744.5393749999999, - "DOP" : 45.39963, - "JEP" : 0.649952, - "LBP" : 1508.578325, - "BTN" : 65.51653399999999, - "BZD" : 1.994645, - "MYR" : 4.295923, - "YER" : 215.146399, - "JMD" : 119.5316, - "TOP" : 2.21008, - "SOS" : 625.730003, - "TMT" : 3.501467, - "MDL" : 19.94576, - "XPD" : 0.001605, - "XOF" : 603.343825, - "TWD" : 32.42717, - "BBD" : 2, - "CAD" : 1.314503, - "CNY" : 6.33528, - "JOD" : 0.7089760000000001, - "XPF" : 109.593574, - "IQD" : 1137.007451, - "HNL" : 21.97698, - "AED" : 3.672977, - "ERN" : 15.14, - "KES" : 101.9965, - "KMF" : 450.566, - "DZD" : 106.9734, - "MKD" : 56.45779, - "CUP" : 0.999838, - "BWP" : 10.575013, - "AZN" : 1.048288, - "SBD" : 7.907656, - "KGS" : 69.732249, - "KHR" : 4057.034976, - "ZMK" : 5253.075255, - "HTG" : 54.158, - "CZK" : 24.86731, - "BAM" : 1.796159, - "IMP" : 0.649952 - }, - "base" : "USD" - }, - "status" : 200, - "url" : "https:\/\/openexchangerates.org\/api\/latest.json?app_id=this_is_not_the_app_id_youre_looking_for", - "headers" : { - "Access-Control-Allow-Origin" : "*", - "Server" : "Apache", - "Connection" : "close", - "Last-Modified" : "Wed, 04 Nov 2015 21:00:11 GMT", - "Content-Type" : "application\/json; charset=utf-8", - "Date" : "Wed, 04 Nov 2015 22:02:22 GMT", - "Content-Length" : "4457", - "Cache-Control" : "public", - "Etag" : "\"3d94fce1847d054ecceea85dafdbe862\"" - } - }, - "request" : { - "method" : "GET", - "url" : "https:\/\/openexchangerates.org\/api\/latest.json?app_id=this_is_not_the_app_id_youre_looking_for" - } - } - ], - "name" : "OpenExchangeRates.org USDEUR" -} diff --git a/Tests/Shared/DVR Cassettes/Yahoo GBPUSD.json b/Tests/Shared/DVR Cassettes/Yahoo GBPUSD.json deleted file mode 100644 index d05e838..0000000 --- a/Tests/Shared/DVR Cassettes/Yahoo GBPUSD.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "interactions" : [ - { - "recorded_at" : 1446743589.787131, - "response" : { - "body" : "IkdCUC9VU0QiLDEuNTIzNwo=", - "status" : 200, - "url" : "https:\/\/download.finance.yahoo.com\/d\/quotes.csv?s=GBPUSD=X&f=nl1", - "headers" : { - "Server" : "ATS", - "Content-Type" : "application\/octet-stream", - "Via" : "http\/1.1 r11.ycpi.loa.yahoo.net (ApacheTrafficServer [cMsSf ])", - "Age" : "0", - "p3p" : "policyref=\"https:\/\/policies.yahoo.com\/w3c\/p3p.xml\", CP=\"CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE LOC GOV\"", - "Date" : "Thu, 05 Nov 2015 17:13:09 GMT", - "Content-Length" : "17", - "Cache-Control" : "private, no-cache, no-store" - } - }, - "request" : { - "method" : "GET", - "url" : "https:\/\/download.finance.yahoo.com\/d\/quotes.csv?s=GBPUSD=X&f=nl1" - } - } - ], - "name" : "Yahoo GBPUSD" -} diff --git a/Tests/Shared/FXOpenExchangeRatesTests.swift b/Tests/Shared/FXOpenExchangeRatesTests.swift deleted file mode 100644 index d284ee7..0000000 --- a/Tests/Shared/FXOpenExchangeRatesTests.swift +++ /dev/null @@ -1,137 +0,0 @@ -// -// FXOpenExchangeRatesTests.swift -// Money -// -// Created by Daniel Thorpe on 04/11/2015. -// -// - -import XCTest -import Result -import DVR -import SwiftyJSON -@testable import Money - -struct MyOpenExchangeRatesAppID: OpenExchangeRatesAppID { - static let app_id = "this_is_not_the_app_id_youre_looking_for" -} - -class OpenExchangeRates: _OpenExchangeRates { } - -class FreeOpenExchangeRates: _ForeverFreeOpenExchangeRates { } - -class FXPaidOpenExchangeRatesTests: FXProviderTests { - typealias Provider = OpenExchangeRates - - func test__name() { - XCTAssertEqual(Provider.name(), "OpenExchangeRates.org GBPJPY") - } - - func test__base_currency() { - XCTAssertEqual(Provider.BaseMoney.Currency.code, Currency.GBP.code) - } - - func test__request__url_does_contain_base() { - guard let url = Provider.request().URL else { - XCTFail("Request did not return a URL") - return - } - - XCTAssertTrue(url.absoluteString.containsString("&base=GBP")) - } -} - -class FXFreeOpenExchangeRatesTests: FXProviderTests { - - typealias Provider = FreeOpenExchangeRates - typealias TestableProvider = TestableFXRemoteProvider - typealias FaultyProvider = FaultyFXRemoteProvider - - func test__name() { - XCTAssertEqual(Provider.name(), "OpenExchangeRates.org USDEUR") - } - - func test__session() { - XCTAssertEqual(Provider.session(), NSURLSession.sharedSession()) - } - - func test__base_currency() { - XCTAssertEqual(Provider.BaseMoney.Currency.code, Currency.USD.code) - } - - func test__request__url_does_not_contain_base() { - guard let url = Provider.request().URL else { - XCTFail("Request did not return a URL") - return - } - - XCTAssertFalse(url.absoluteString.containsString("&base=")) - } - - func test__quote_adaptor__with_network_error() { - let error = NSError(domain: NSURLErrorDomain, code: NSURLError.BadServerResponse.rawValue, userInfo: nil) - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(error: error) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.NetworkError(error)) - } - - func test__quote_adaptor__with_no_data() { - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(value: (.None, .None)) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.NoData) - } - - func test__quote_adaptor__with_garbage_data() { - let data = createGarbageData() - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(value: (data, .None)) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.InvalidData(data)) - } - - func test__quote_adaptor__with_missing_rate() { - var json = dvrJSONFromCassette(Provider.name())! - var rates: Dictionary = json["rates"].dictionary! - rates.removeValueForKey("EUR") - json["rates"] = JSON(rates) - let data = try! json.rawData() - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(value: (data, .None)) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.RateNotFound(Provider.name())) - } - - func test__faulty_provider() { - let expectation = expectationWithDescription("Test: \(__FUNCTION__)") - - FaultyProvider.fx(100) { result in - guard let error = result.error else { - XCTFail("Should have received a network error.") - return - } - switch error { - case .NetworkError(_): - break // This is the success path. - default: - XCTFail("Returned \(error), should be a .NetworkError") - } - expectation.fulfill() - } - - waitForExpectationsWithTimeout(1, handler: nil) - } - - func test__fx() { - let expectation = expectationWithDescription("Test: \(__FUNCTION__)") - - TestableProvider.fx(100) { result in - if let usd = result.value { - XCTAssertEqual(usd, 92.09) - } - else { - XCTFail("Received error: \(result.error!).") - } - expectation.fulfill() - } - - waitForExpectationsWithTimeout(1, handler: nil) - } -} diff --git a/Tests/Shared/FXTests.swift b/Tests/Shared/FXTests.swift deleted file mode 100644 index c32f39e..0000000 --- a/Tests/Shared/FXTests.swift +++ /dev/null @@ -1,170 +0,0 @@ -// -// FXTests.swift -// Money -// -// Created by Daniel Thorpe on 02/11/2015. -// -// - -import XCTest -import Result -import SwiftyJSON -import DVR -@testable import Money - -class Sessions { - - static func sessionWithCassetteName(name: String) -> Session { - return sharedInstance.sessionWithCassetteName(name) - } - - static let sharedInstance = Sessions() - - var sessions = Dictionary() - - func sessionWithCassetteName(name: String) -> Session { - guard let session = sessions[name] else { - let _session = Session(cassetteName: name) - sessions.updateValue(_session, forKey: name) - return _session - } - return session - } -} - -class TestableFXRemoteProvider: FXRemoteProviderType { - - typealias CounterMoney = Provider.CounterMoney - typealias BaseMoney = Provider.BaseMoney - - static func name() -> String { - return Provider.name() - } - - static func session() -> NSURLSession { - return Sessions.sessionWithCassetteName(name()) - } - - static func request() -> NSURLRequest { - return Provider.request() - } - - static func quoteFromNetworkResult(result: Result<(NSData?, NSURLResponse?), NSError>) -> Result { - return Provider.quoteFromNetworkResult(result) - } -} - -class FaultyFXRemoteProvider: FXRemoteProviderType { - - typealias CounterMoney = Provider.CounterMoney - typealias BaseMoney = Provider.BaseMoney - - static func name() -> String { - return Provider.name() - } - - static func session() -> NSURLSession { - return Provider.session() - } - - static func request() -> NSURLRequest { - let request = Provider.request() - if let url = request.URL, - host = url.host, - modified = NSURL(string: url.absoluteString.stringByReplacingOccurrencesOfString(host, withString: "broken-host.xyz")) { - return NSURLRequest(URL: modified) - } - return request - } - - static func quoteFromNetworkResult(result: Result<(NSData?, NSURLResponse?), NSError>) -> Result { - return Provider.quoteFromNetworkResult(result) - } -} - - -class FakeLocalFX: FXLocalProviderType { - - typealias BaseMoney = B - typealias CounterMoney = C - - static func name() -> String { - return "LocalFX" - } - - static func quote() -> FXQuote { - return FXQuote(rate: 1.1) - } -} - - -class FXErrorTests: XCTestCase { - - func test__fx_error__equality() { - XCTAssertNotEqual(FXError.NoData, FXError.RateNotFound("whatever")) - } -} - -class FXProviderTests: XCTestCase { - - func dvrJSONFromCassette(name: String) -> JSON? { - guard let path = NSBundle(forClass: self.dynamicType).pathForResource(name, ofType: "json"), - data = NSData(contentsOfFile: path) else { - return .None - } - let json = JSON(data: data) - let body = json[["interactions",0,"response","body"]] - return body - } -} - -class FXLocalProviderTests: XCTestCase { - - func test_fx() { - XCTAssertEqual(FakeLocalFX.fx(100).counter, 110) - } -} - -class FXQuoteTests: XCTestCase { - - var quote: FXQuote! - - func archiveEncodedQuote() -> NSData { - return NSKeyedArchiver.archivedDataWithRootObject(quote.encoded) - } - - func unarchive(archive: NSData) -> FXQuote? { - return FXQuote.decode(NSKeyedUnarchiver.unarchiveObjectWithData(archive)) - } - - func test__quote_encodes() { - quote = FXQuote(rate: 1.5409) - XCTAssertEqual(unarchive(archiveEncodedQuote())!.rate, quote.rate) - } -} - -class FXTransactionTests: XCTestCase { - - typealias Transaction = FXTransaction - - var transaction: Transaction! - - func archiveEncodedTransaction() -> NSData { - return NSKeyedArchiver.archivedDataWithRootObject(transaction.encoded) - } - - func unarchive(archive: NSData) -> Transaction? { - return Transaction.decode(NSKeyedUnarchiver.unarchiveObjectWithData(archive)) - } - - func test__transaction_encodes() { - transaction = Transaction(base: 100, quote: FXQuote(rate: 1.2)) - XCTAssertEqual(unarchive(archiveEncodedTransaction())!.base, 100) - } -} diff --git a/Tests/Shared/FXYahooTests.swift b/Tests/Shared/FXYahooTests.swift deleted file mode 100644 index 6b6d6be..0000000 --- a/Tests/Shared/FXYahooTests.swift +++ /dev/null @@ -1,99 +0,0 @@ -// -// FXYahooTests.swift -// Money -// -// Created by Daniel Thorpe on 04/11/2015. -// -// - -import XCTest -import Result -import DVR -@testable import Money - -class FXYahooTests: FXProviderTests { - - typealias Provider = Yahoo - typealias TestableProvider = TestableFXRemoteProvider - typealias FaultyProvider = FaultyFXRemoteProvider - - func test__name() { - XCTAssertEqual(Provider.name(), "Yahoo GBPUSD") - } - - func test__session() { - XCTAssertEqual(Provider.session(), NSURLSession.sharedSession()) - } - - func test__quote_adaptor__with_network_error() { - let error = NSError(domain: NSURLErrorDomain, code: NSURLError.BadServerResponse.rawValue, userInfo: nil) - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(error: error) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.NetworkError(error)) - } - - func test__quote_adaptor__with_no_data() { - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(value: (.None, .None)) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.NoData) - } - - func test__quote_adaptor__with_garbage_data() { - let data = createGarbageData() - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(value: (data, .None)) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.InvalidData(data)) - } - - func test__quote_adaptor__with_incorrect_text_response() { - let text = "This isn't a correct response" - let data = text.dataUsingEncoding(NSUTF8StringEncoding) - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(value: (data, .None)) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.InvalidData(data!)) - } - - func test__quote_adaptor__with_missing_rate() { - let text = "This,could be,a correct,response" - let data = text.dataUsingEncoding(NSUTF8StringEncoding) - let network: Result<(NSData?, NSURLResponse?), NSError> = Result(value: (data, .None)) - let quote = Provider.quoteFromNetworkResult(network) - XCTAssertEqual(quote.error!, FXError.RateNotFound(text)) - } - - func test__faulty_provider() { - let expectation = expectationWithDescription("Test: \(__FUNCTION__)") - - FaultyProvider.fx(100) { result in - guard let error = result.error else { - XCTFail("Should have received a network error.") - return - } - switch error { - case .NetworkError(_): - break // This is the success path. - default: - XCTFail("Returned \(error), should be a .NetworkError") - } - expectation.fulfill() - } - - waitForExpectationsWithTimeout(1, handler: nil) - } - - func test__fx() { - let expectation = expectationWithDescription("Test: \(__FUNCTION__)") - - TestableProvider.fx(100) { result in - if let usd = result.value { - XCTAssertEqual(usd, 152.37) - } - else { - XCTFail("Received error: \(result.error!).") - } - expectation.fulfill() - } - - waitForExpectationsWithTimeout(1, handler: nil) - } -} \ No newline at end of file diff --git a/Tests/Shared/MoneyTests.swift b/Tests/Shared/MoneyTests.swift index 99deb86..15aa851 100644 --- a/Tests/Shared/MoneyTests.swift +++ b/Tests/Shared/MoneyTests.swift @@ -9,18 +9,6 @@ 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 MoneyTests: XCTestCase { var money: Money! diff --git a/Tests/Shared/Troll.png b/Tests/Shared/Troll.png deleted file mode 100644 index 0bbe2f9..0000000 Binary files a/Tests/Shared/Troll.png and /dev/null differ