diff --git a/.gitignore b/.gitignore index 86935ad8..8feebb27 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ Packages/ # Carthage Carthage/Build +report.xml +fastlane/test_output +fastlane/build_output diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 00000000..c043eea7 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.2.1 diff --git a/.travis.yml b/.travis.yml index a36615d2..8005621f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,22 +1,12 @@ language: objective-c -osx_image: xcode7.3 +osx_image: xcode8 +cache: bundler +rvm: 2.2.1 install: -- gem install xcpretty --no-rdoc --no-ri --no-document -- gem install jazzy --no-rdoc --no-ri --no-document -- curl -OlL "https://github.com/Carthage/Carthage/releases/download/0.11/Carthage.pkg" -- sudo installer -pkg "Carthage.pkg" -target / -- rm "Carthage.pkg" + - bundle install + - brew outdated carthage || brew upgrade carthage script: -- open -b com.apple.iphonesimulator # Travis CI workaround -- set -o pipefail && xcodebuild test -scheme 'Freddy' -sdk macosx | xcpretty -c -- set -o pipefail && xcodebuild test -scheme 'MobileFreddy' -sdk iphonesimulator -destination - 'platform=iOS Simulator,name=iPhone 5' | xcpretty -c -- set -o pipefail && xcodebuild test -scheme 'TVFreddy' -sdk appletvsimulator -destination - 'platform=tvOS Simulator,name=Apple TV 1080p' | xcpretty -c -- carthage build --no-skip-current -- pod lib lint --quick -after_success: -- "./Configurations/publish_docs.sh" + - bundle exec fastlane travis notifications: slack: secure: VHcEZcTuVR3gfHIcM9jcxrXgE3tkVIT4gWDLpnK7O4em86dCpaVkLDwr0UcQYxvqGS1J8pQqGZCwyOBsdgaItX52eRDMIez/384B56Vl6eufdLAcwWELIEtHyFkJ6XUjmASICaeeb8SpF/rj89/AXoHU6c8shY13NKtoBBZCGq8= diff --git a/Configurations/Base.xcconfig b/Configurations/Base.xcconfig index 1ebc4d82..b296c239 100644 --- a/Configurations/Base.xcconfig +++ b/Configurations/Base.xcconfig @@ -26,8 +26,10 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR CLANG_WARN__DUPLICATE_METHOD_MATCH = YES GCC_WARN_UNDECLARED_SELECTOR = YES CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR +CLANG_WARN_INFINITE_RECURSION = YES +CLANG_WARN_SUSPICIOUS_MOVE = YES -CURRENT_PROJECT_VERSION = 2.1.0 +CURRENT_PROJECT_VERSION = 3.0.0 VERSION_INFO_PREFIX = VERSIONING_SYSTEM = apple-generic @@ -39,8 +41,9 @@ TVOS_DEPLOYMENT_TARGET = 9.0 ENABLE_BITCODE = YES ENABLE_BITCODE[sdk=macosx*] = NO -CODE_SIGN_IDENTITY[sdk=macosx*] = - -CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer -CODE_SIGN_IDENTITY[sdk=appletvos*] = iPhone Developer +CODE_SIGN_IDENTITY[sdk=macosx*] = +CODE_SIGN_IDENTITY[sdk=iphoneos*] = +CODE_SIGN_IDENTITY[sdk=appletvos*] = +CODE_SIGN_IDENTITY[sdk=watchos*] = -SWIFT_VERSION = 2.3 +SWIFT_VERSION = 3.0 diff --git a/Freddy.podspec b/Freddy.podspec index a4cccf45..689e234c 100644 --- a/Freddy.podspec +++ b/Freddy.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "Freddy" - s.version = "2.1.0" + s.version = "3.0.0" s.summary = "A JSON parsing library written in Swift" s.description = <<-DESC @@ -28,5 +28,5 @@ Pod::Spec.new do |s| s.source_files = "Sources/**/*.{h,swift}" s.requires_arc = true - + s.pod_target_xcconfig = { 'SWIFT_VERSION' => '3.0' } end diff --git a/Freddy.xcodeproj/project.pbxproj b/Freddy.xcodeproj/project.pbxproj index 0e55cbe8..936976b7 100644 --- a/Freddy.xcodeproj/project.pbxproj +++ b/Freddy.xcodeproj/project.pbxproj @@ -70,6 +70,12 @@ DB6ADFC71C23631500D77BF1 /* sampleNoWhiteSpace.JSON in Resources */ = {isa = PBXBuildFile; fileRef = DB6ADFC21C23631500D77BF1 /* sampleNoWhiteSpace.JSON */; }; DB6ADFC81C23631500D77BF1 /* sampleNoWhiteSpace.JSON in Resources */ = {isa = PBXBuildFile; fileRef = DB6ADFC21C23631500D77BF1 /* sampleNoWhiteSpace.JSON */; }; DC194EB91C47D87B001D4569 /* JSONTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC194EB81C47D87B001D4569 /* JSONTests.swift */; }; + DC5F54FB1D82E79400670855 /* JSONTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC194EB81C47D87B001D4569 /* JSONTests.swift */; }; + DC5F54FC1D82E79500670855 /* JSONTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC194EB81C47D87B001D4569 /* JSONTests.swift */; }; + DC5F54FD1D82E79900670855 /* JSONEncodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C67C72A1C3B32A6003D5A05 /* JSONEncodableTests.swift */; }; + DC5F54FE1D82E79A00670855 /* JSONEncodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C67C72A1C3B32A6003D5A05 /* JSONEncodableTests.swift */; }; + DC5F54FF1D82E79F00670855 /* JSONSubscriptingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7BD51E1C7A4B9300A6ED4B /* JSONSubscriptingTests.swift */; }; + DC5F55001D82E7A000670855 /* JSONSubscriptingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7BD51E1C7A4B9300A6ED4B /* JSONSubscriptingTests.swift */; }; E43B67DB1C59598700ACE390 /* JSONEncodingDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = E43B67DA1C59598700ACE390 /* JSONEncodingDetector.swift */; }; E43B67DC1C59598700ACE390 /* JSONEncodingDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = E43B67DA1C59598700ACE390 /* JSONEncodingDetector.swift */; }; E43B67DD1C59598700ACE390 /* JSONEncodingDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = E43B67DA1C59598700ACE390 /* JSONEncodingDetector.swift */; }; @@ -451,14 +457,16 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; - LastUpgradeCheck = 0720; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Big Nerd Ranch"; TargetAttributes = { DB6ADF1E1C23610B00D77BF1 = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; }; DB6ADF281C23610B00D77BF1 = { CreatedOnToolsVersion = 7.2; + LastSwiftMigration = 0800; }; DB6ADF3D1C23612000D77BF1 = { CreatedOnToolsVersion = 7.2; @@ -585,8 +593,11 @@ DB6ADFB51C2362FF00D77BF1 /* JSONParserTests.swift in Sources */, E43B67E11C5962CD00ACE390 /* JSONEncodingDetectorTests.swift in Sources */, 3F70EA991C6D0EC500972CEB /* JSONSerializingTests.swift in Sources */, + DC5F54FF1D82E79F00670855 /* JSONSubscriptingTests.swift in Sources */, DB6ADFBB1C2362FF00D77BF1 /* JSONTypeTests.swift in Sources */, + DC5F54FD1D82E79900670855 /* JSONEncodableTests.swift in Sources */, DB6ADFB21C2362FF00D77BF1 /* JSONDecodableTests.swift in Sources */, + DC5F54FB1D82E79400670855 /* JSONTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -646,8 +657,11 @@ DB6ADFB61C2362FF00D77BF1 /* JSONParserTests.swift in Sources */, E43B67E21C5962CD00ACE390 /* JSONEncodingDetectorTests.swift in Sources */, 3F70EA9A1C6D0EC500972CEB /* JSONSerializingTests.swift in Sources */, + DC5F55001D82E7A000670855 /* JSONSubscriptingTests.swift in Sources */, DB6ADFBC1C2362FF00D77BF1 /* JSONTypeTests.swift in Sources */, + DC5F54FE1D82E79A00670855 /* JSONEncodableTests.swift in Sources */, DB6ADFB31C2362FF00D77BF1 /* JSONDecodableTests.swift in Sources */, + DC5F54FC1D82E79500670855 /* JSONTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -745,6 +759,7 @@ baseConfigurationReference = DB6ADF811C23617500D77BF1 /* Framework.xcconfig */; buildSettings = { SDKROOT = macosx; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -753,6 +768,7 @@ baseConfigurationReference = DB6ADF811C23617500D77BF1 /* Framework.xcconfig */; buildSettings = { SDKROOT = macosx; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -761,6 +777,7 @@ baseConfigurationReference = DB6ADF831C23617500D77BF1 /* Tests.xcconfig */; buildSettings = { SDKROOT = macosx; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -769,6 +786,7 @@ baseConfigurationReference = DB6ADF831C23617500D77BF1 /* Tests.xcconfig */; buildSettings = { SDKROOT = macosx; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/Freddy.xcodeproj/xcshareddata/xcschemes/Freddy.xcscheme b/Freddy.xcodeproj/xcshareddata/xcschemes/Freddy.xcscheme index 5531789f..7cbb854a 100644 --- a/Freddy.xcodeproj/xcshareddata/xcschemes/Freddy.xcscheme +++ b/Freddy.xcodeproj/xcshareddata/xcschemes/Freddy.xcscheme @@ -1,6 +1,6 @@ 0.7) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + addressable (2.4.0) + babosa (1.0.2) + cert (1.4.2) + fastlane_core (>= 0.50.3, < 1.0.0) + spaceship (>= 0.32.0, < 1.0.0) + claide (1.0.0) + cocoapods (1.0.1) + activesupport (>= 4.0.2) + claide (>= 1.0.0, < 2.0) + cocoapods-core (= 1.0.1) + cocoapods-deintegrate (>= 1.0.0, < 2.0) + cocoapods-downloader (>= 1.0.0, < 2.0) + cocoapods-plugins (>= 1.0.0, < 2.0) + cocoapods-search (>= 1.0.0, < 2.0) + cocoapods-stats (>= 1.0.0, < 2.0) + cocoapods-trunk (>= 1.0.0, < 2.0) + cocoapods-try (>= 1.0.0, < 2.0) + colored (~> 1.2) + escape (~> 0.0.4) + fourflusher (~> 0.3.0) + molinillo (~> 0.4.5) + nap (~> 1.0) + xcodeproj (>= 1.1.0, < 2.0) + cocoapods-core (1.0.1) + activesupport (>= 4.0.2) + fuzzy_match (~> 2.0.4) + nap (~> 1.0) + cocoapods-deintegrate (1.0.1) + cocoapods-downloader (1.1.1) + cocoapods-plugins (1.0.0) + nap + cocoapods-search (1.0.0) + cocoapods-stats (1.0.0) + cocoapods-trunk (1.0.0) + nap (>= 0.8, < 2.0) + netrc (= 0.7.8) + cocoapods-try (1.1.0) + colored (1.2) + commander (4.4.0) + highline (~> 1.7.2) + credentials_manager (0.16.0) + colored + commander (>= 4.3.5) + highline (>= 1.7.1) + security + deliver (1.13.3) + credentials_manager (>= 0.16.0, < 1.0.0) + fastimage (~> 1.6) + fastlane_core (>= 0.50.3, < 1.0.0) + plist (~> 3.1.0) + spaceship (>= 0.31.6, < 1.0.0) + domain_name (0.5.20160826) + unf (>= 0.0.5, < 1.0.0) + dotenv (2.1.1) + escape (0.0.4) + excon (0.45.4) + faraday (0.9.2) + multipart-post (>= 1.2, < 3) + faraday-cookie_jar (0.0.6) + faraday (>= 0.7.4) + http-cookie (~> 1.0.0) + faraday_middleware (0.10.0) + faraday (>= 0.7.4, < 0.10) + fastimage (1.6.8) + addressable (~> 2.3, >= 2.3.5) + fastlane (1.102.0) + activesupport (< 5) + addressable (~> 2.3) + bundler (~> 1.12) + cert (>= 1.4.1, < 2.0.0) + credentials_manager (>= 0.16.0, < 1.0.0) + deliver (>= 1.13.3, < 2.0.0) + fastlane_core (>= 0.50.2, < 1.0.0) + frameit (>= 2.7.0, < 3.0.0) + gym (>= 1.7.0, < 2.0.0) + krausefx-shenzhen (>= 0.14.10) + match (>= 0.6.3, < 1.0.0) + multipart-post (~> 2.0.0) + pem (>= 1.3.2, < 2.0.0) + pilot (>= 1.10.0, < 2.0.0) + plist (~> 3.1.0) + produce (>= 1.2.0, < 2.0.0) + scan (>= 0.11.3, < 2.0.0) + screengrab (>= 0.5.0, < 1.0.0) + sigh (>= 1.10.0, < 2.0.0) + slack-notifier (~> 1.3) + snapshot (>= 1.14.0, < 2.0.0) + spaceship (>= 0.32.0, < 1.0.0) + supply (>= 0.7.0, < 1.0.0) + terminal-notifier (~> 1.6.2) + terminal-table (~> 1.4.5) + word_wrap (~> 1.0.0) + xcode-install (~> 2.0.0) + xcodeproj (>= 0.20, < 2.0.0) + xcpretty (>= 0.2.1) + fastlane_core (0.52.0) + babosa + colored + commander (>= 4.4.0, <= 5.0.0) + credentials_manager (>= 0.16.0, < 1.0.0) + excon (~> 0.45.0) + gh_inspector (>= 1.0.1, < 2.0.0) + highline (>= 1.7.2) + json + multi_json + plist (~> 3.1) + rubyzip (~> 1.1.6) + terminal-table (~> 1.4.5) + fourflusher (0.3.2) + frameit (2.7.0) + deliver (> 0.3) + fastimage (~> 1.6.3) + fastlane_core (>= 0.36.1, < 1.0.0) + mini_magick (~> 4.5.1) + fuzzy_match (2.0.4) + gh_inspector (1.0.2) + google-api-client (0.9.13) + addressable (~> 2.3) + googleauth (~> 0.5) + httpclient (~> 2.7) + hurley (~> 0.1) + memoist (~> 0.11) + mime-types (>= 1.6) + representable (~> 2.3.0) + retriable (~> 2.0) + googleauth (0.5.1) + faraday (~> 0.9) + jwt (~> 1.4) + logging (~> 2.0) + memoist (~> 0.12) + multi_json (~> 1.11) + os (~> 0.9) + signet (~> 0.7) + gym (1.9.0) + fastlane_core (>= 0.51.0, < 1.0.0) + plist + rubyzip (>= 1.1.7) + terminal-table + xcpretty (>= 0.2.1) + highline (1.7.8) + http-cookie (1.0.2) + domain_name (~> 0.5) + httpclient (2.8.2.4) + hurley (0.2) + i18n (0.7.0) + jazzy (0.7.1) + cocoapods (~> 1.0) + mustache (~> 0.99) + open4 + redcarpet (~> 3.2) + rouge (~> 1.5) + sass (~> 3.4) + sqlite3 (~> 1.3) + xcinvoke (~> 0.2.1) + json (1.8.3) + jwt (1.5.4) + krausefx-shenzhen (0.14.10) + commander (>= 4.3, < 5.0) + dotenv (>= 0.7) + faraday (~> 0.9) + faraday_middleware (~> 0.9) + highline (>= 1.7.2) + json (~> 1.8) + net-sftp (~> 2.1.2) + plist (~> 3.1.0) + rubyzip (~> 1.1) + security (~> 0.1.3) + terminal-table (~> 1.4.5) + liferaft (0.0.4) + little-plugger (1.1.4) + logging (2.1.0) + little-plugger (~> 1.1) + multi_json (~> 1.10) + match (0.6.4) + cert (>= 1.4.1, < 2.0.0) + credentials_manager (>= 0.16.0, < 1.0.0) + fastlane_core (>= 0.50.3, < 1.0.0) + security + sigh (>= 1.10.2, < 2.0.0) + spaceship (>= 0.31.10, < 1.0.0) + memoist (0.15.0) + mime-types (3.1) + mime-types-data (~> 3.2015) + mime-types-data (3.2016.0521) + mini_magick (4.5.1) + minitest (5.9.0) + molinillo (0.4.5) + multi_json (1.12.1) + multi_xml (0.5.5) + multipart-post (2.0.0) + mustache (0.99.8) + nap (1.1.0) + net-sftp (2.1.2) + net-ssh (>= 2.6.5) + net-ssh (3.2.0) + netrc (0.7.8) + open4 (1.3.4) + os (0.9.6) + pem (1.3.2) + fastlane_core (>= 0.43.1, < 1.0.0) + spaceship (>= 0.26.2, < 1.0.0) + pilot (1.10.0) + credentials_manager (>= 0.3.0) + fastlane_core (>= 0.46.2, < 1.0.0) + spaceship (>= 0.29.0, < 1.0.0) + terminal-table (~> 1.4.5) + plist (3.1.0) + produce (1.2.0) + fastlane_core (>= 0.30.0, < 1.0.0) + spaceship (>= 0.31.1, < 1.0.0) + redcarpet (3.3.4) + representable (2.3.0) + uber (~> 0.0.7) + retriable (2.1.0) + rouge (1.11.1) + rubyzip (1.1.7) + sass (3.4.22) + scan (0.12.1) + fastlane_core (>= 0.51.0, < 1.0.0) + slack-notifier (~> 1.3) + terminal-table + xcpretty (>= 0.2.1) + xcpretty-travis-formatter (>= 0.0.3) + screengrab (0.5.2) + fastlane_core (>= 0.50.3, < 1.0.0) + security (0.1.3) + sigh (1.10.2) + fastlane_core (>= 0.36.1, < 1.0.0) + plist (~> 3.1) + spaceship (>= 0.29.1, < 1.0.0) + signet (0.7.3) + addressable (~> 2.3) + faraday (~> 0.9) + jwt (~> 1.5) + multi_json (~> 1.10) + slack-notifier (1.5.1) + snapshot (1.14.0) + fastimage (~> 1.6.3) + fastlane_core (>= 0.50.3, < 1.0.0) + plist (~> 3.1.0) + xcpretty (>= 0.2.1) + spaceship (0.32.1) + colored + credentials_manager (>= 0.16.0) + faraday (~> 0.9) + faraday-cookie_jar (~> 0.0.6) + faraday_middleware (~> 0.9) + fastimage (~> 1.6) + multi_xml (~> 0.5) + plist (~> 3.1) + sqlite3 (1.3.11) + supply (0.7.1) + credentials_manager (>= 0.15.0) + fastlane_core (>= 0.43.4) + google-api-client (~> 0.9.1) + terminal-notifier (1.6.3) + terminal-table (1.4.5) + thread_safe (0.3.5) + tzinfo (1.2.2) + thread_safe (~> 0.1) + uber (0.0.15) + unf (0.1.4) + unf_ext + unf_ext (0.0.7.2) + word_wrap (1.0.0) + xcinvoke (0.2.1) + liferaft (~> 0.0.4) + xcode-install (2.0.5) + claide (>= 0.9.1, < 1.1.0) + spaceship (>= 0.25.1, < 1.0.0) + xcodeproj (1.3.1) + activesupport (>= 3) + claide (>= 1.0.0, < 2.0) + colored (~> 1.2) + xcpretty (0.2.2) + rouge (~> 1.8) + xcpretty-travis-formatter (0.0.4) + xcpretty (~> 0.2, >= 0.0.7) + +PLATFORMS + ruby + +DEPENDENCIES + cocoapods + fastlane + jazzy + xcpretty + +RUBY VERSION + ruby 2.2.1p85 + +BUNDLED WITH + 1.12.5 diff --git a/README.md b/README.md index 707353fb..e357e8b0 100644 --- a/README.md +++ b/README.md @@ -56,14 +56,14 @@ Here is a quick example on how to parse this data using Freddy: let data = getSomeData() do { let json = try JSON(data: data) - let success = try json.bool("success") + let success = try json.getBool(at: "success") // do something with `success` } catch { // do something with the error } ``` -After we load in the data, we create an instance of `JSON`, the workhorse of this framework. This allows us to access the values from the JSON data. We `try` because the `data` may be malformed and the parsing could generate an error. Next, we access the `"success"` key by calling the `bool(_:)` method on `JSON`. We `try` here as well because accessing the `json` for the key `"success"` could fail - e.g., if we had passed an unknown key. This method takes two parameters, both of which are used to define a path into the `JSON` instance to find a Boolean value of interest. If a `Bool` is found at the path described by `"success"`, then `bool(_:)` returns a `Bool`. If the path does not lead to a `Bool`, then an appropriate error is thrown. +After we load in the data, we create an instance of `JSON`, the workhorse of this framework. This allows us to access the values from the JSON data. We `try` because the `data` may be malformed and the parsing could generate an error. Next, we access the `"success"` key by calling the `getBool(at:)` method on `JSON`. We `try` here as well because accessing the `json` for the key `"success"` could fail - e.g., if we had passed an unknown key. This method takes two parameters, both of which are used to define a path into the `JSON` instance to find a Boolean value of interest. If a `Bool` is found at the path described by `"success"`, then `getBool(at:)` returns a `Bool`. If the path does not lead to a `Bool`, then an appropriate error is thrown. #### Use Paths to Access Nested Data with Subscripting With Freddy, it is possible to use a path to access elements deeper in the json structure. For example: @@ -72,16 +72,16 @@ With Freddy, it is possible to use a path to access elements deeper in the json let data = getSomeData() do { let json = try JSON(data: data) - let georgiaZipCodes = try json.array("states","Georgia") - let firstPersonName = try json.string("people",0,"name") + let georgiaZipCodes = try json.getArray(at: "states","Georgia") + let firstPersonName = try json.getString(at: "people",0,"name") } catch { // do something with the error } ``` -In the code `json.array("states","Georgia")`, the keys `"states"` and `"Georgia"` describe a path to the Georgia zip codes within `json`. +In the code `json.getArray(at: "states","Georgia")`, the keys `"states"` and `"Georgia"` describe a path to the Georgia zip codes within `json`. `Freddy`'s parlance calls this process "subscripting" the JSON. -What is typed between the parentheses of, for example, `array(_:)` is a comma-separated list of keys and indices that describe the path to a value of interest. +What is typed between the parentheses of, for example, `getArray(at:)` is a comma-separated list of keys and indices that describe the path to a value of interest. There can be any number of subscripts, and each subscript can be either a `String` indicating a named element in the JSON, or an `Int` that represents an element in an array. If there is something invalid in the path such as an index that doesn't exist in the JSON, an error will be thrown. @@ -94,14 +94,14 @@ Now, let's look an example that parses the data into a model class: let data = getSomeData() do { let json = try JSON(data: data) - let people = try json.array("people").map(Person.init) + let people = try json.getArray(at: "people").map(Person.init) // do something with `people` } catch { // do something with the error } ``` -Here, we are instead loading the values from the key `"people"` as an array using the method `array(_:)`. This method works a lot like the `bool(_:)` method you saw above. It uses the path provided to the method to find an array. If the path is good, the method will return an `Array` of `JSON`. If the path is bad, then an appropriate error is thrown. +Here, we are instead loading the values from the key `"people"` as an array using the method `getArray(at:)`. This method works a lot like the `getBool(at:)` method you saw above. It uses the path provided to the method to find an array. If the path is good, the method will return an `Array` of `JSON`. If the path is bad, then an appropriate error is thrown. We can then call `map` on that `JSON` array. Since the `Person` type conforms to `JSONDecodable`, we can pass in the `Person` type's initializer. This call applies an initializer that takes an instance of `JSON` to each element in the array, producing an array of `Person` instances. @@ -126,40 +126,44 @@ public struct Person { extension Person: JSONDecodable { public init(json value: JSON) throws { - name = try value.string("name") - age = try value.int("age") - spouse = try value.bool("spouse") + name = try value.getString(at: "name") + age = try value.getInt(at: "age") + spouse = try value.getBool(at: "spouse") } } ``` -`Person` just has a few properties. It conforms to `JSONDecodable` via an extension. In the extension, we implement a `throws`ing initializer that takes an instance of `JSON` as its sole parameter. In the implementation, we `try` three functions: 1) `string(_:)`, 2) `int(_:)`, and 3) `bool(_:)`. Each of these works as you have seen before. The methods take in a path, which is used to find a value of a specific type within the `JSON` instance passed to the initializer. Since these paths could be bad, or the requested type may not match what is actually inside of the `JSON`, these methods may potentially throw an error. +`Person` just has a few properties. It conforms to `JSONDecodable` via an extension. In the extension, we implement a `throws`ing initializer that takes an instance of `JSON` as its sole parameter. In the implementation, we `try` three functions: 1) `getString(at:)`, 2) `getInt(at:)`, and 3) `getBool(at:)`. Each of these works as you have seen before. The methods take in a path, which is used to find a value of a specific type within the `JSON` instance passed to the initializer. Since these paths could be bad, or the requested type may not match what is actually inside of the `JSON`, these methods may potentially throw an error. ### Serialization Freddy's serialization support centers around the `JSON.serialize()` method. #### Basic Usage -The `JSON` enumeration supports conversion to `NSData` directly: +The `JSON` enumeration supports conversion to `Data` directly: ```swift let someJSON: JSON = … -let data: NSData = try someJSON.serialize() +do { + let data: Data = try someJSON.serialize() +} catch { + // Handle error +} ``` #### JSONEncodable: Serializing Other Objects Most of your objects aren't `Freddy.JSON` objects, though. -You can serialize them to `NSData` by first converting them to a +You can serialize them to `Data` by first converting them to a `Freddy.JSON` via `JSONEncodable.toJSON()`, the sole method of the -`JSONEncodable` protocol, and then using `serialize()` to convert -the `Freddy.JSON` to `NSData`: +`JSONEncodable` protocol, and then use `serialize()` to convert +the `Freddy.JSON` to `Data`: ```swift let myObject: JSONEncodable = … -// Object -> JSON -> NSData: +// Object -> JSON -> Data: let objectAsJSON: JSON = myObject.toJSON() -let data: NSData = try objectAsJSON.serialize() +let data: Data = try objectAsJSON.serialize() // More concisely: let dataOneLiner = try object.toJSON().serialize() @@ -172,10 +176,10 @@ and implement that protocol's `toJSON()` method: ```swift extension Person: JSONEncodable { public func toJSON() -> JSON { - return .Dictionary([ - "name": .String(name), - "age": .Int(age), - "spouse": .Bool(spouse)]) + return .dictionary([ + "name": .string(name), + "age": .int(age), + "spouse": .bool(spouse)]) } } ``` @@ -184,9 +188,7 @@ extension Person: JSONEncodable { ## Getting Started -Freddy requires iOS 7.0, Mac OS X 10.9, watchOS 2.0, or tvOS 9.0. Linux is not yet supported. - -Dynamic frameworks on iOS require a minimum deployment target of iOS 8.0. For a project targeting iOS 7, see ["Submodules"](https://github.com/bignerdranch/Freddy#submodules). +Freddy requires iOS 8.0, Mac OS X 10.9, watchOS 2.0, or tvOS 9.0. Linux is not yet supported. You have a few different options to install Freddy. @@ -195,7 +197,7 @@ You have a few different options to install Freddy. Add us to your `Cartfile`: ``` -github "bignerdranch/Freddy" ~> 2.1 +github "bignerdranch/Freddy" ~> 3.0 ``` After running `carthage bootstrap`, add `Freddy.framework` to the "Linked Frameworks and Libraries" panel of your application target. [Read more](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application). @@ -232,16 +234,14 @@ import PackageDescription let package = Package( name: "My Nerdy App", dependencies: [ - .Package(url: "https://github.com/bignerdranch/Freddy.git", majorVersion: 2), + .Package(url: "https://github.com/bignerdranch/Freddy.git", majorVersion: 3), ] ) ``` ### iOS 7 -If you would like to use Freddy with iOS 7, then you will need to copy Freddy's source files into your project. -Embedded frameworks are only supported in iOS 8+. -You can add Freddy as a submodule (see above), and then make sure to add the source files to your project. +If you would like to use Freddy with iOS 7, then you will need to use a previous release of Freddy. ## Setting Breakpoint Errors diff --git a/Configurations/publish_docs.sh b/Resources/scripts/publish_docs.sh similarity index 100% rename from Configurations/publish_docs.sh rename to Resources/scripts/publish_docs.sh diff --git a/Resources/scripts/validate_carthage.sh b/Resources/scripts/validate_carthage.sh new file mode 100755 index 00000000..0a8ec308 --- /dev/null +++ b/Resources/scripts/validate_carthage.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# +# Bootstraps Carthage to validate that everything builds as expected. +# thanks to abbeycode/UnzipKit for example +# + +EXIT_CODE=0 + +clone_project() { + local BRANCH_NAME BUILD_DIR + if [[ $CIRCLECI ]]; then + BRANCH_NAME=$CIRCLE_BRANCH + BUILD_DIR=$(pwd) + elif [[ $TRAVIS ]]; then + BRANCH_NAME=$TRAVIS_BRANCH + BUILD_DIR=$TRAVIS_BUILD_DIR + else + BUILD_DIR="$HOME/workspace/CoreDataStack" + BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD) + echo "=================Not Running in CI=================" + fi + + echo "=================Creating Cartfile=================" + echo "git \"$BUILD_DIR\" \"$BRANCH_NAME\"" > ./Cartfile +} + +bootstrap() { + echo "=================Bootstrapping Carthage=================" + carthage bootstrap --configuration Debug + EXIT_CODE=$? +} + +validate() { + echo "=================Checking for build products=================" + + if [ ! -d "Carthage/Build/iOS/CoreDataStack.framework" ]; then + echo "=================iOS Library failed to build with Carthage=================" + EXIT_CODE=1 + fi + + if [ ! -d "Carthage/Build/tvOS/CoreDataStack.framework" ]; then + echo "=================iOS Library failed to build with Carthage=================" + EXIT_CODE=1 + fi +} + +clean_up() { + echo "=================Cleaning Up=================" + rm ./Cartfile + rm ./Cartfile.resolved + rm -rf ./Carthage +} + +clone_project +bootstrap +validate +clean_up +exit $EXIT_CODE diff --git a/Sources/JSON.swift b/Sources/JSON.swift index bcbf8c84..ebe2a923 100644 --- a/Sources/JSON.swift +++ b/Sources/JSON.swift @@ -9,19 +9,19 @@ /// An enum to describe the structure of JSON. public enum JSON { /// A case for denoting an array with an associated value of `[JSON]` - case Array([JSON]) + case array([JSON]) /// A case for denoting a dictionary with an associated value of `[Swift.String: JSON]` - case Dictionary([Swift.String: JSON]) + case dictionary([String: JSON]) /// A case for denoting a double with an associated value of `Swift.Double`. - case Double(Swift.Double) + case double(Double) /// A case for denoting an integer with an associated value of `Swift.Int`. - case Int(Swift.Int) + case int(Int) /// A case for denoting a string with an associated value of `Swift.String`. - case String(Swift.String) + case string(String) /// A case for denoting a boolean with an associated value of `Swift.Bool`. - case Bool(Swift.Bool) + case bool(Bool) /// A case for denoting null. - case Null + case null } // MARK: - Errors @@ -29,21 +29,21 @@ public enum JSON { extension JSON { /// An enum to encapsulate errors that may arise in working with `JSON`. - public enum Error: ErrorType { + public enum Error: Swift.Error { /// The `index` is out of bounds for a JSON array - case IndexOutOfBounds(index: Swift.Int) + case indexOutOfBounds(index: Int) /// The `key` was not found in the JSON dictionary - case KeyNotFound(key: Swift.String) + case keyNotFound(key: String) /// The JSON is not subscriptable with `type` - case UnexpectedSubscript(type: JSONPathType.Type) + case unexpectedSubscript(type: JSONPathType.Type) /// Unexpected JSON `value` was found that is not convertible `to` type - case ValueNotConvertible(value: JSON, to: Any.Type) + case valueNotConvertible(value: JSON, to: Any.Type) /// The JSON is not serializable to a `String`. - case StringSerializationError + case stringSerializationError } } @@ -53,23 +53,23 @@ extension JSON { /// Return `true` if `lhs` is equal to `rhs`. public func ==(lhs: JSON, rhs: JSON) -> Bool { switch (lhs, rhs) { - case (.Array(let arrL), .Array(let arrR)): + case (.array(let arrL), .array(let arrR)): return arrL == arrR - case (.Dictionary(let dictL), .Dictionary(let dictR)): + case (.dictionary(let dictL), .dictionary(let dictR)): return dictL == dictR - case (.String(let strL), .String(let strR)): + case (.string(let strL), .string(let strR)): return strL == strR - case (.Double(let dubL), .Double(let dubR)): + case (.double(let dubL), .double(let dubR)): return dubL == dubR - case (.Double(let dubL), .Int(let intR)): + case (.double(let dubL), .int(let intR)): return dubL == Double(intR) - case (.Int(let intL), .Int(let intR)): + case (.int(let intL), .int(let intR)): return intL == intR - case (.Int(let intL), .Double(let dubR)): + case (.int(let intL), .double(let dubR)): return Double(intL) == dubR - case (.Bool(let bL), .Bool(let bR)): + case (.bool(let bL), .bool(let bR)): return bL == bR - case (.Null, .Null): + case (.null, .null): return true default: return false @@ -85,13 +85,13 @@ extension JSON: CustomStringConvertible { /// A textual representation of `self`. public var description: Swift.String { switch self { - case .Array(let arr): return Swift.String(arr) - case .Dictionary(let dict): return Swift.String(dict) - case .String(let string): return string - case .Double(let double): return Swift.String(double) - case .Int(let int): return Swift.String(int) - case .Bool(let bool): return Swift.String(bool) - case .Null: return "null" + case .array(let arr): return String(describing: arr) + case .dictionary(let dict): return String(describing: dict) + case .string(let string): return string + case .double(let double): return String(describing: double) + case .int(let int): return String(describing: int) + case .bool(let bool): return String(describing: bool) + case .null: return "null" } } diff --git a/Sources/JSONDecodable.swift b/Sources/JSONDecodable.swift index 2da9bae0..7a047036 100644 --- a/Sources/JSONDecodable.swift +++ b/Sources/JSONDecodable.swift @@ -28,12 +28,12 @@ extension Double: JSONDecodable { /// passed to this initializer. public init(json: JSON) throws { switch json { - case let .Double(double): + case let .double(double): self = double - case let .Int(int): - self = Swift.Double(int) + case let .int(int): + self = Double(int) default: - throw JSON.Error.ValueNotConvertible(value: json, to: Swift.Double) + throw JSON.Error.valueNotConvertible(value: json, to: Double.self) } } @@ -48,12 +48,12 @@ extension Int: JSONDecodable { /// passed to this initializer. public init(json: JSON) throws { switch json { - case let .Double(double) where double <= Double(Swift.Int.max): - self = Swift.Int(double) - case let .Int(int): + case let .double(double) where double <= Double(Int.max): + self = Int(double) + case let .int(int): self = int default: - throw JSON.Error.ValueNotConvertible(value: json, to: Swift.Int) + throw JSON.Error.valueNotConvertible(value: json, to: Int.self) } } @@ -67,18 +67,17 @@ extension String: JSONDecodable { /// an instance of `String` cannot be created from the `JSON` value that was /// passed to this initializer. public init(json: JSON) throws { - switch json { - case let .String(string): + case let .string(string): self = string - case let .Int(int): + case let .int(int): self = String(int) - case let .Bool(bool): + case let .bool(bool): self = String(bool) - case let .Double(double): + case let .double(double): self = String(double) default: - throw JSON.Error.ValueNotConvertible(value: json, to: Swift.String) + throw JSON.Error.valueNotConvertible(value: json, to: String.self) } } @@ -92,8 +91,8 @@ extension Bool: JSONDecodable { /// an instance of `Bool` cannot be created from the `JSON` value that was /// passed to this initializer. public init(json: JSON) throws { - guard case let .Bool(bool) = json else { - throw JSON.Error.ValueNotConvertible(value: json, to: Swift.Bool) + guard case let .bool(bool) = json else { + throw JSON.Error.valueNotConvertible(value: json, to: Bool.self) } self = bool } @@ -110,7 +109,7 @@ extension RawRepresentable where RawValue: JSONDecodable { public init(json: JSON) throws { let raw = try json.decode(type: RawValue.self) guard let value = Self(rawValue: raw) else { - throw JSON.Error.ValueNotConvertible(value: json, to: Self.self) + throw JSON.Error.valueNotConvertible(value: json, to: Self.self) } self = value } @@ -123,10 +122,10 @@ internal extension JSON { /// - returns: An `Array` of `JSON` elements /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`. /// - seealso: `JSON.decode(_:type:)` - static func getArray(json: JSON) throws -> [JSON] { + static func getArray(from json: JSON) throws -> [JSON] { // Ideally should be expressed as a conditional protocol implementation on Swift.Array. - guard case let .Array(array) = json else { - throw Error.ValueNotConvertible(value: json, to: Swift.Array) + guard case let .array(array) = json else { + throw Error.valueNotConvertible(value: json, to: Swift.Array) } return array } @@ -136,38 +135,39 @@ internal extension JSON { /// - returns: An `Dictionary` of `String` mapping to `JSON` elements /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`. /// - seealso: `JSON.decode(_:type:)` - static func getDictionary(json: JSON) throws -> [Swift.String: JSON] { + static func getDictionary(from json: JSON) throws -> [String: JSON] { // Ideally should be expressed as a conditional protocol implementation on Swift.Dictionary. - guard case let .Dictionary(dictionary) = json else { - throw Error.ValueNotConvertible(value: json, to: Swift.Dictionary) + guard case let .dictionary(dictionary) = json else { + throw Error.valueNotConvertible(value: json, to: Swift.Dictionary) } return dictionary } /// Attempts to decode many values from a descendant JSON array at a path /// into JSON. - /// - parameter: A `JSON` to be used to create the returned `Array` of some type conforming to `JSONDecodable`. + /// - parameter json: A `JSON` to be used to create the returned `Array` of some type conforming to `JSONDecodable`. /// - returns: An `Array` of `Decoded` elements. /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`, as /// well as any error that arises from decoding the contained values. /// - seealso: `JSON.decode(_:type:)` - static func getArrayOf(json: JSON) throws -> [Decoded] { + static func decodedArray(from json: JSON) throws -> [Decoded] { // Ideally should be expressed as a conditional protocol implementation on Swift.Dictionary. // This implementation also doesn't do the `type = Type.self` trick. - return try getArray(json).map(Decoded.init) + return try getArray(from: json).map(Decoded.init) } /// Attempts to decode many values from a descendant JSON object at a path /// into JSON. + /// - parameter json: A `JSON` to be used to create the returned `Dictionary` of some type conforming to `JSONDecodable`. /// - returns: A `Dictionary` of string keys and `Decoded` values. /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)` or /// any error that arises from decoding the contained values. /// - seealso: `JSON.decode(_:type:)` - static func getDictionaryOf(json: JSON) throws -> [Swift.String: Decoded] { - guard case let .Dictionary(dictionary) = json else { - throw Error.ValueNotConvertible(value: json, to: Swift.Dictionary) + static func decodedDictionary(from json: JSON) throws -> [Swift.String: Decoded] { + guard case let .dictionary(dictionary) = json else { + throw Error.valueNotConvertible(value: json, to: Swift.Dictionary) } - var decodedDictionary = Swift.Dictionary(minimumCapacity: dictionary.count) + var decodedDictionary = Swift.Dictionary(minimumCapacity: dictionary.count) for (key, value) in dictionary { decodedDictionary[key] = try Decoded(json: value) } diff --git a/Sources/JSONEncodable.swift b/Sources/JSONEncodable.swift index 480c57bc..7da5fd00 100644 --- a/Sources/JSONEncodable.swift +++ b/Sources/JSONEncodable.swift @@ -13,64 +13,64 @@ public protocol JSONEncodable { /// Converts an instance of a conforming type to `JSON`. /// - returns: An instance of `JSON`. /// - Note: If conforming to `JSONEncodable` with a custom type of your own, you should return an instance of - /// `JSON.Dictionary`. + /// `JSON.dictionary`. func toJSON() -> JSON } extension Array where Element: JSONEncodable { /// Converts an instance of `Array` whose elements conform to `JSONEncodable` to `JSON`. - /// - returns: An instance of `JSON` where the enum case is `.Array`. + /// - returns: An instance of `JSON` where the enum case is `.array`. public func toJSON() -> JSON { let arrayOfJSON = self.map { $0.toJSON() } - return .Array(arrayOfJSON) + return .array(arrayOfJSON) } } extension Dictionary where Value: JSONEncodable { /// Converts an instance of `Dictionary` whose values conform to `JSONEncodable` to `JSON`. The keys in the resulting - /// `JSON.Dictionary` will be of type `String`. - /// - returns: An instance of `JSON` where the enum case is `.Dictionary`. + /// `JSON.dictionary` will be of type `String`. + /// - returns: An instance of `JSON` where the enum case is `.dictionary`. public func toJSON() -> JSON { var jsonDictionary = [String: JSON]() for (k, v) in self { - let key = String(k) + let key = String(describing: k) jsonDictionary[key] = v.toJSON() } - return .Dictionary(jsonDictionary) + return .dictionary(jsonDictionary) } } extension Int: JSONEncodable { /// Converts an instance of a conforming type to `JSON`. - /// - returns: An instance of `JSON` where the enum case is `.Int`. + /// - returns: An instance of `JSON` where the enum case is `.int`. public func toJSON() -> JSON { - return .Int(self) + return .int(self) } } extension Double: JSONEncodable { /// Converts an instance of a conforming type to `JSON`. - /// - returns: An instance of `JSON` where the enum case is `.Double`. + /// - returns: An instance of `JSON` where the enum case is `.double`. public func toJSON() -> JSON { - return .Double(self) + return .double(self) } } extension String: JSONEncodable { /// Converts an instance of a conforming type to `JSON`. - /// - returns: An instance of `JSON` where the enum case is `.String`. + /// - returns: An instance of `JSON` where the enum case is `.string`. public func toJSON() -> JSON { - return .String(self) + return .string(self) } } extension Bool: JSONEncodable { /// Converts an instance of a conforming type to `JSON`. - /// - returns: An instance of `JSON` where the enum case is `.Bool`. + /// - returns: An instance of `JSON` where the enum case is `.bool`. public func toJSON() -> JSON { - return .Bool(self) + return .bool(self) } } diff --git a/Sources/JSONEncodingDetector.swift b/Sources/JSONEncodingDetector.swift index 933bc0c2..84410f19 100644 --- a/Sources/JSONEncodingDetector.swift +++ b/Sources/JSONEncodingDetector.swift @@ -12,19 +12,19 @@ public struct JSONEncodingDetector { //// The Unicode encodings looked for during detection public enum Encoding { //// UTF-8 - case UTF8 + case utf8 //// UTF-16 Little Endian - case UTF16LE + case utf16LE //// UTF-16 Big Endian - case UTF16BE + case utf16BE //// UTF-32 Little Endian - case UTF32LE + case utf32LE //// UTF-32 Big Endian - case UTF32BE + case utf32BE } //// The Unicode encodings supported by JSONParser.swift - public static let supportedEncodings: [Encoding] = [.UTF8] + public static let supportedEncodings: [Encoding] = [.utf8] typealias ByteStreamPrefixInformation = (encoding: Encoding, byteOrderMarkLength: Int) @@ -56,10 +56,10 @@ public struct JSONEncodingDetector { //// //// - parameter header: The front Slice of data being read and evaluated. //// - returns: A tuple containing the detected Unicode encoding and the lenght of the byte order mark. - static func detectEncoding(header: Slice>) -> ByteStreamPrefixInformation { + static func detectEncoding(_ header: RandomAccessSlice>) -> ByteStreamPrefixInformation { guard let prefix = prefixFromHeader(header) else { - return (.UTF8, 0) + return (.utf8, 0) } if let prefixInfo = JSONEncodingDetector.encodingFromBOM(prefix) { @@ -67,22 +67,22 @@ public struct JSONEncodingDetector { } else { switch prefix { case(0, 0, 0?, _): - return (.UTF32BE, 0) + return (.utf32BE, 0) case(_, 0, 0?, 0?): - return (.UTF32LE, 0) + return (.utf32LE, 0) case (0, _, 0?, _), (0, _, _, _): - return (.UTF16BE, 0) + return (.utf16BE, 0) case (_, 0, _, 0?), (_, 0, _, _): - return (.UTF16LE, 0) + return (.utf16LE, 0) default: - return (.UTF8, 0) + return (.utf8, 0) } } } private typealias EncodingBytePrefix = (UInt8, UInt8, UInt8?, UInt8?) - private static func prefixFromHeader(header: Slice>) -> EncodingBytePrefix? { + private static func prefixFromHeader(_ header: RandomAccessSlice>) -> EncodingBytePrefix? { if header.count >= 4 { return(header[0], header[1], header[2], header[3]) } else if header.count >= 2 { @@ -91,18 +91,18 @@ public struct JSONEncodingDetector { return nil } - private static func encodingFromBOM(prefix: EncodingBytePrefix) -> ByteStreamPrefixInformation? { + private static func encodingFromBOM(_ prefix: EncodingBytePrefix) -> ByteStreamPrefixInformation? { switch prefix { case(0xFE, 0xFF, _, _): - return (.UTF16BE, 2) + return (.utf16BE, 2) case(0x00, 0x00, 0xFE?, 0xFF?): - return (.UTF32BE, 4) + return (.utf32BE, 4) case(0xEF, 0xBB, 0xBF?, _): - return (.UTF8, 3) + return (.utf8, 3) case(0xFF, 0xFE, 0?, 0?): - return (.UTF32LE, 4) + return (.utf32LE, 4) case(0xFF, 0xFE, _, _): - return (.UTF16LE, 2) + return (.utf16LE, 2) default: return nil } diff --git a/Sources/JSONLiteralConvertible.swift b/Sources/JSONLiteralConvertible.swift index b90e0526..88542881 100644 --- a/Sources/JSONLiteralConvertible.swift +++ b/Sources/JSONLiteralConvertible.swift @@ -8,12 +8,12 @@ // MARK: - ArrayLiteralConvertible -extension JSON: ArrayLiteralConvertible { +extension JSON: ExpressibleByArrayLiteral { /// Create an instance by copying each element of the `collection` into a /// new `Array`. - public init(_ collection: Collection) { - self = .Array(Swift.Array(collection)) + public init(_ collection: Collection) where Collection.Iterator.Element == JSON { + self = .array(Swift.Array(collection)) } /// Create an instance initialized with `elements`. @@ -25,32 +25,36 @@ extension JSON: ArrayLiteralConvertible { // MARK: - DictionaryLiteralConvertible -extension JSON: DictionaryLiteralConvertible { - +extension JSON: ExpressibleByDictionaryLiteral { + /// Create an instance by copying each key/value pair of the `pairs` into /// a new `Dictionary`. - public init(_ pairs: Dictionary) { - var dictionary = Swift.Dictionary(minimumCapacity: pairs.underestimateCount()) + public init(_ pairs: Dictionary) where Dictionary.Iterator.Element == (Swift.String, JSON) { + var dictionary = Swift.Dictionary(minimumCapacity: pairs.underestimatedCount) for (key, value) in pairs { dictionary[key] = value } - self = .Dictionary(dictionary) + self.init(dictionary) } - + /// Create an instance initialized with `pairs`. public init(dictionaryLiteral pairs: (Swift.String, JSON)...) { self.init(pairs) } + /// Create an instance initialized to `dictionary`. + public init(_ dictionary: Swift.Dictionary) { + self = .dictionary(dictionary) + } } // MARK: - FloatLiteralConvertible -extension JSON: FloatLiteralConvertible { +extension JSON: ExpressibleByFloatLiteral { /// Create an instance initialized to `Double` `value`. public init(_ value: Swift.Double) { - self = .Double(value) + self = .double(value) } /// Create a literal instance initialized to `value`. @@ -62,11 +66,11 @@ extension JSON: FloatLiteralConvertible { // MARK: - IntegerLiteralConvertible -extension JSON: IntegerLiteralConvertible { +extension JSON: ExpressibleByIntegerLiteral { /// Create an instance initialized to `Int` by `value`. public init(_ value: Swift.Int) { - self = .Int(value) + self = .int(value) } /// Create a literal instance initialized to `value`. @@ -78,11 +82,11 @@ extension JSON: IntegerLiteralConvertible { // MARK: - StringLiteralConvertible -extension JSON: StringLiteralConvertible { +extension JSON: ExpressibleByStringLiteral { /// Create an instance initialized to `String` by `text`. public init(_ text: Swift.String) { - self = .String(text) + self = .string(text) } /// Create a literal instance initialized to `value`. @@ -104,11 +108,11 @@ extension JSON: StringLiteralConvertible { // MARK: - BooleanLiteralConvertible -extension JSON: BooleanLiteralConvertible { +extension JSON: ExpressibleByBooleanLiteral { /// Create an instance initialized to `Bool` by `value`. public init(_ value: Swift.Bool) { - self = .Bool(value) + self = .bool(value) } /// Create a literal instance initialized to `value`. @@ -120,11 +124,11 @@ extension JSON: BooleanLiteralConvertible { // MARK: - NilLiteralConvertible -extension JSON: NilLiteralConvertible { +extension JSON: ExpressibleByNilLiteral { /// Create an instance initialized with `nil`. public init(nilLiteral: ()) { - self = .Null + self = .null } } diff --git a/Sources/JSONParser.swift b/Sources/JSONParser.swift index b98a4f8d..31ddaa9b 100644 --- a/Sources/JSONParser.swift +++ b/Sources/JSONParser.swift @@ -71,19 +71,17 @@ private let ParserMaximumDepth = 512 /// input and it does not allow trailing commas in arrays or dictionaries. public struct JSONParser { - private enum Sign: Int { - case Positive = 1 - case Negative = -1 + fileprivate enum Sign: Int { + case positive = 1 + case negative = -1 } private let input: UnsafeBufferPointer - private let owner: Any? private var loc = 0 private var depth = 0 - private init(buffer: UnsafeBufferPointer, owner: T) { - self.input = buffer - self.owner = owner + fileprivate init(input: UnsafeBufferPointer) { + self.input = input } /// Decode the root element of the `JSON` stream. This may be any fragment @@ -100,18 +98,18 @@ public struct JSONParser { let value = try parseValue() skipWhitespace() guard loc == input.count else { - throw Error.EndOfStreamGarbage(offset: loc) + throw Error.endOfStreamGarbage(offset: loc) } return value } private mutating func parseValue() throws -> JSON { guard depth <= ParserMaximumDepth else { - throw Error.ExceededNestingLimit(offset: loc) + throw Error.exceededNestingLimit(offset: loc) } guard input.count > 0 else { - throw Error.EndOfStreamUnexpected + throw Error.endOfStreamUnexpected } advancing: while loc < input.count { @@ -140,29 +138,28 @@ public struct JSONParser { return try decodeTrue() case Literal.MINUS: - return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .LeadingMinus)) + return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .leadingMinus)) case Literal.zero: - return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .LeadingZero)) + return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .leadingZero)) case Literal.one...Literal.nine: - return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .PreDecimalDigits)) + return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .preDecimalDigits)) case Literal.SPACE, Literal.TAB, Literal.RETURN, Literal.NEWLINE: - loc = loc.successor() + loc = (loc + 1) default: break advancing } - } catch let InternalError.NumberOverflow(offset: start) { - return try decodeNumberAsString(start) + } catch let InternalError.numberOverflow(offset: start) { + return try decodeNumberAsString(from: start) } } - if loc < input.count { - throw Error.ValueInvalid(offset: loc, character: UnicodeScalar(input[loc])) + throw Error.valueInvalid(offset: loc, character: UnicodeScalar(input[loc])) } else { - throw Error.EndOfStreamUnexpected + throw Error.endOfStreamUnexpected } } @@ -170,8 +167,7 @@ public struct JSONParser { while loc < input.count { switch input[loc] { case Literal.SPACE, Literal.TAB, Literal.RETURN, Literal.NEWLINE: - loc = loc.successor() - + loc = (loc + 1) default: return } @@ -182,66 +178,65 @@ public struct JSONParser { let header = input.prefix(4) let encodingPrefixInformation = JSONEncodingDetector.detectEncoding(header) guard JSONEncodingDetector.supportedEncodings.contains(encodingPrefixInformation.encoding) else { - throw Error.InvalidUnicodeStreamEncoding(detectedEncoding: encodingPrefixInformation.encoding) + throw Error.invalidUnicodeStreamEncoding(detectedEncoding: encodingPrefixInformation.encoding) } - loc = loc.advancedBy(encodingPrefixInformation.byteOrderMarkLength) + loc = loc.advanced(by: encodingPrefixInformation.byteOrderMarkLength) } private mutating func decodeNull() throws -> JSON { - guard loc.advancedBy(3, limit: input.count) != input.count else { - throw Error.LiteralNilMisspelled(offset: loc) + guard input.index(loc, offsetBy: 3, limitedBy: input.count) != input.count else { + throw Error.literalNilMisspelled(offset: loc) } if input[loc+1] != Literal.u || input[loc+2] != Literal.l || input[loc+3] != Literal.l { - throw Error.LiteralNilMisspelled(offset: loc) + throw Error.literalNilMisspelled(offset: loc) } loc += 4 - return .Null + return .null } private mutating func decodeTrue() throws -> JSON { - guard loc.advancedBy(3, limit: input.count) != input.count else { - throw Error.LiteralTrueMisspelled(offset: loc) + guard input.index(loc, offsetBy: 3, limitedBy: input.count) != input.count else { + throw Error.literalNilMisspelled(offset: loc) } if input[loc+1] != Literal.r || input[loc+2] != Literal.u || input[loc+3] != Literal.e { - throw Error.LiteralTrueMisspelled(offset: loc) + throw Error.literalTrueMisspelled(offset: loc) } loc += 4 - return .Bool(true) + return .bool(true) } private mutating func decodeFalse() throws -> JSON { - guard loc.advancedBy(4, limit: input.count) != input.count else { - throw Error.LiteralFalseMisspelled(offset: loc) + guard input.index(loc, offsetBy: 4, limitedBy: input.count) != input.count else { + throw Error.literalNilMisspelled(offset: loc) } if input[loc+1] != Literal.a || input[loc+2] != Literal.l || input[loc+3] != Literal.s || input[loc+4] != Literal.e { - throw Error.LiteralFalseMisspelled(offset: loc) + throw Error.literalFalseMisspelled(offset: loc) } loc += 5 - return .Bool(false) + return .bool(false) } private var stringDecodingBuffer = [UInt8]() private mutating func decodeString() throws -> JSON { - let start = loc - loc = loc.successor() - stringDecodingBuffer.removeAll(keepCapacity: true) + loc = (loc + 1) + stringDecodingBuffer.removeAll(keepingCapacity: true) while loc < input.count { switch input[loc] { case Literal.BACKSLASH: - loc = loc.successor() + loc = (loc + 1) switch input[loc] { case Literal.DOUBLE_QUOTE: stringDecodingBuffer.append(Literal.DOUBLE_QUOTE) case Literal.BACKSLASH: stringDecodingBuffer.append(Literal.BACKSLASH) @@ -252,7 +247,7 @@ public struct JSONParser { case Literal.t: stringDecodingBuffer.append(Literal.TAB) case Literal.n: stringDecodingBuffer.append(Literal.NEWLINE) case Literal.u: - loc = loc.successor() + loc = (loc + 1) try readUnicodeEscape(start: loc - 2) // readUnicodeEscape() advances loc on its own, so we'll `continue` now @@ -260,29 +255,27 @@ public struct JSONParser { continue default: - throw Error.ControlCharacterUnrecognized(offset: loc) + throw Error.controlCharacterUnrecognized(offset: loc) } - loc = loc.successor() + loc = (loc + 1) case Literal.DOUBLE_QUOTE: - loc = loc.successor() + loc = (loc + 1) stringDecodingBuffer.append(0) - guard let string = (stringDecodingBuffer.withUnsafeBufferPointer { - String.fromCString(UnsafePointer($0.baseAddress)) - }) else { - throw Error.UnicodeEscapeInvalid(offset: start) + let string = stringDecodingBuffer.withUnsafeBufferPointer { + String(cString: UnsafePointer($0.baseAddress!)) } - - return .String(string) + + return .string(string) case let other: stringDecodingBuffer.append(other) - loc = loc.successor() + loc = (loc + 1) } } - throw Error.EndOfStreamUnexpected + throw Error.endOfStreamUnexpected } private mutating func readCodeUnit() -> UInt16? { @@ -312,9 +305,9 @@ public struct JSONParser { return codeUnit } - private mutating func readUnicodeEscape(start start: Int) throws { + private mutating func readUnicodeEscape(start: Int) throws { guard let codeUnit = readCodeUnit() else { - throw Error.UnicodeEscapeInvalid(offset: start) + throw Error.unicodeEscapeInvalid(offset: start) } let codeUnits: [UInt16] @@ -324,51 +317,53 @@ public struct JSONParser { // First confirm and skip over that we have another "\u" guard loc + 6 <= input.count && input[loc] == Literal.BACKSLASH && input[loc+1] == Literal.u else { - throw Error.UnicodeEscapeInvalid(offset: start) + throw Error.unicodeEscapeInvalid(offset: start) } loc += 2 // Ensure the second code unit is valid for the surrogate pair - guard let secondCodeUnit = readCodeUnit() where UTF16.isTrailSurrogate(secondCodeUnit) else { - throw Error.UnicodeEscapeInvalid(offset: start) + guard let secondCodeUnit = readCodeUnit(), UTF16.isTrailSurrogate(secondCodeUnit) else { + throw Error.unicodeEscapeInvalid(offset: start) } codeUnits = [codeUnit, secondCodeUnit] } else { codeUnits = [codeUnit] } - - let transcodeHadError = transcode(UTF16.self, UTF8.self, codeUnits.generate(), { self.stringDecodingBuffer.append($0) }, stopOnError: true) + + let transcodeHadError = transcode(codeUnits.makeIterator(), from: UTF16.self, to: UTF8.self, stoppingOnError: true) { (outputEncodingCodeUnit) in + self.stringDecodingBuffer.append(outputEncodingCodeUnit) + } if transcodeHadError { - throw Error.UnicodeEscapeInvalid(offset: start) + throw Error.unicodeEscapeInvalid(offset: start) } } private mutating func decodeArray() throws -> JSON { let start = loc - loc = loc.successor() + loc = (loc + 1) var items = [JSON]() while loc < input.count { skipWhitespace() if loc < input.count && input[loc] == Literal.RIGHT_BRACKET { - loc = loc.successor() - return .Array(items) + loc = (loc + 1) + return .array(items) } if !items.isEmpty { guard loc < input.count && input[loc] == Literal.COMMA else { - throw Error.CollectionMissingSeparator(offset: start) + throw Error.collectionMissingSeparator(offset: start) } - loc = loc.successor() + loc = (loc + 1) } items.append(try parseValue()) } - throw Error.EndOfStreamUnexpected + throw Error.endOfStreamUnexpected } // Decoding objects can be recursive, so we have to keep more than one @@ -384,13 +379,13 @@ public struct JSONParser { mutating func getBuffer() -> [(String,JSON)] { if !buffers.isEmpty { var buffer = buffers.removeLast() - buffer.removeAll(keepCapacity: true) + buffer.removeAll(keepingCapacity: true) return buffer } return [(String,JSON)]() } - mutating func putBuffer(buffer: [(String,JSON)]) { + mutating func putBuffer(_ buffer: [(String,JSON)]) { buffers.append(buffer) } } @@ -399,210 +394,207 @@ public struct JSONParser { private mutating func decodeObject() throws -> JSON { let start = loc - loc = loc.successor() + loc = (loc + 1) var pairs = decodeObjectBuffers.getBuffer() while loc < input.count { skipWhitespace() if loc < input.count && input[loc] == Literal.RIGHT_BRACE { - loc = loc.successor() + loc = (loc + 1) var obj = [String:JSON](minimumCapacity: pairs.count) for (k, v) in pairs { obj[k] = v } decodeObjectBuffers.putBuffer(pairs) - return .Dictionary(obj) + return .dictionary(obj) } if !pairs.isEmpty { guard loc < input.count && input[loc] == Literal.COMMA else { - throw Error.CollectionMissingSeparator(offset: start) + throw Error.collectionMissingSeparator(offset: start) } - loc = loc.successor() + loc = (loc + 1) skipWhitespace() } guard loc < input.count && input[loc] == Literal.DOUBLE_QUOTE else { - throw Error.DictionaryMissingKey(offset: start) + throw Error.dictionaryMissingKey(offset: start) } - let key = try decodeString().string() + let key = try decodeString().getString() skipWhitespace() guard loc < input.count && input[loc] == Literal.COLON else { - throw Error.CollectionMissingSeparator(offset: start) + throw Error.collectionMissingSeparator(offset: start) } - loc = loc.successor() + loc = (loc + 1) pairs.append((key, try parseValue())) } - throw Error.EndOfStreamUnexpected + throw Error.endOfStreamUnexpected } - private mutating func decodeIntegralValue(parser: NumberParser) throws -> JSON { - var sign = Sign.Positive + private mutating func decodeIntegralValue(_ parser: NumberParser) throws -> JSON { + var sign = Sign.positive var parser = parser var value = 0 // This would be more natural as `while true { ... }` with a meaningful .Done case, // but that causes compile time explosion in Swift 2.2. :-| - while parser.state != .Done { + while parser.state != .done { switch parser.state { - case .LeadingMinus: - sign = .Negative + case .leadingMinus: + sign = .negative try parser.parseNegative() - case .LeadingZero: + case .leadingZero: parser.parseLeadingZero() - case .PreDecimalDigits: + case .preDecimalDigits: try parser.parsePreDecimalDigits { c in guard case let (exponent, false) = Int.multiplyWithOverflow(10, value) else { - throw InternalError.NumberOverflow(offset: parser.start) + throw InternalError.numberOverflow(offset: parser.start) } guard case let (newValue, false) = Int.addWithOverflow(exponent, Int(c - Literal.zero)) else { - throw InternalError.NumberOverflow(offset: parser.start) + throw InternalError.numberOverflow(offset: parser.start) } value = newValue } - case .Decimal, .Exponent: - return try detectingFloatingPointErrors(parser.start) { + case .decimal, .exponent: + return try detectingFloatingPointErrors(start: parser.start) { try decodeFloatingPointValue(parser, sign: sign, value: Double(value)) } - case .PostDecimalDigits, .ExponentSign, .ExponentDigits: + case .postDecimalDigits, .exponentSign, .exponentDigits: assertionFailure("Invalid internal state while parsing number") - case .Done: + case .done: fatalError("impossible condition") } } guard case let (signedValue, false) = Int.multiplyWithOverflow(sign.rawValue, value) else { - throw InternalError.NumberOverflow(offset: parser.start) + throw InternalError.numberOverflow(offset: parser.start) } loc = parser.loc - return .Int(signedValue) + return .int(signedValue) } - private mutating func decodeFloatingPointValue(parser: NumberParser, sign: Sign, value: Double) throws -> JSON { + private mutating func decodeFloatingPointValue(_ parser: NumberParser, sign: Sign, value: Double) throws -> JSON { var parser = parser var value = value - var exponentSign = Sign.Positive + var exponentSign = Sign.positive var exponent = Double(0) var position = 0.1 // This would be more natural as `while true { ... }` with a meaningful .Done case, // but that causes compile time explosion in Swift 2.2. :-| - while parser.state != .Done { + while parser.state != .done { switch parser.state { - case .LeadingMinus, .LeadingZero, .PreDecimalDigits: + case .leadingMinus, .leadingZero, .preDecimalDigits: assertionFailure("Invalid internal state while parsing number") - case .Decimal: + case .decimal: try parser.parseDecimal() - case .PostDecimalDigits: + case .postDecimalDigits: parser.parsePostDecimalDigits { c in value += position * Double(c - Literal.zero) position /= 10 } - case .Exponent: + case .exponent: exponentSign = try parser.parseExponent() - case .ExponentSign: + case .exponentSign: try parser.parseExponentSign() - case .ExponentDigits: + case .exponentDigits: parser.parseExponentDigits { c in exponent = exponent * 10 + Double(c - Literal.zero) } - case .Done: + case .done: fatalError("impossible condition") } } loc = parser.loc - return .Double(Double(sign.rawValue) * value * pow(10, Double(exponentSign.rawValue) * exponent)) + return .double(Double(sign.rawValue) * value * pow(10, Double(exponentSign.rawValue) * exponent)) } - private mutating func decodeNumberAsString(start: Int) throws -> JSON { + + private mutating func decodeNumberAsString(from position: Int) throws -> JSON { var parser: NumberParser = { let state: NumberParser.State - switch input[start] { - case Literal.MINUS: state = .LeadingMinus - case Literal.zero: state = .LeadingZero - case Literal.one...Literal.nine: state = .PreDecimalDigits + switch input[position] { + case Literal.MINUS: state = .leadingMinus + case Literal.zero: state = .leadingZero + case Literal.one...Literal.nine: state = .preDecimalDigits default: fatalError("Internal error: decodeNumber called on not-a-number") } - return NumberParser(loc: start, input: input, state: state) + return NumberParser(loc: position, input: input, state: state) }() - stringDecodingBuffer.removeAll(keepCapacity: true) + stringDecodingBuffer.removeAll(keepingCapacity: true) while true { switch parser.state { - case .LeadingMinus: + case .leadingMinus: try parser.parseNegative() stringDecodingBuffer.append(Literal.MINUS) - case .LeadingZero: + case .leadingZero: parser.parseLeadingZero() stringDecodingBuffer.append(Literal.zero) - case .PreDecimalDigits: + case .preDecimalDigits: parser.parsePreDecimalDigits { stringDecodingBuffer.append($0) } - case .Decimal: + case .decimal: try parser.parseDecimal() stringDecodingBuffer.append(Literal.PERIOD) - case .PostDecimalDigits: + case .postDecimalDigits: parser.parsePostDecimalDigits { stringDecodingBuffer.append($0) } - case .Exponent: + case .exponent: stringDecodingBuffer.append(input[parser.loc]) _ = try parser.parseExponent() - case .ExponentSign: + case .exponentSign: stringDecodingBuffer.append(input[parser.loc]) try parser.parseExponentSign() - case .ExponentDigits: + case .exponentDigits: parser.parseExponentDigits { stringDecodingBuffer.append($0) } - case .Done: + case .done: stringDecodingBuffer.append(0) - guard let string = (stringDecodingBuffer.withUnsafeBufferPointer { - String.fromCString(UnsafePointer($0.baseAddress)) - }) else { - // Should never fail - any problems with the number string should - // result in thrown errors above - fatalError("Internal error: Invalid numeric string") + let string = stringDecodingBuffer.withUnsafeBufferPointer { + String(cString: UnsafePointer($0.baseAddress!)) } loc = parser.loc - return .String(string) + return .string(string) } } } - private func detectingFloatingPointErrors(loc: Int, @noescape _ f: () throws -> T) throws -> T { + private func detectingFloatingPointErrors(start loc: Int, _ f: () throws -> T) throws -> T { let flags = FE_UNDERFLOW | FE_OVERFLOW feclearexcept(flags) let value = try f() guard fetestexcept(flags) == 0 else { - throw InternalError.NumberOverflow(offset: loc) + throw InternalError.numberOverflow(offset: loc) } return value } @@ -610,15 +602,15 @@ public struct JSONParser { private struct NumberParser { enum State { - case LeadingMinus - case LeadingZero - case PreDecimalDigits - case Decimal - case PostDecimalDigits - case Exponent - case ExponentSign - case ExponentDigits - case Done + case leadingMinus + case leadingZero + case preDecimalDigits + case decimal + case postDecimalDigits + case exponent + case exponentSign + case exponentDigits + case done } let start: Int @@ -635,61 +627,61 @@ private struct NumberParser { } mutating func parseNegative() throws { - assert(state == .LeadingMinus, "Unexpected state entering parseNegative") + assert(state == .leadingMinus, "Unexpected state entering parseNegative") - loc = loc.successor() + loc = (loc + 1) guard loc < input.count else { - throw JSONParser.Error.EndOfStreamUnexpected + throw JSONParser.Error.endOfStreamUnexpected } switch input[loc] { case Literal.zero: - state = .LeadingZero + state = .leadingZero case Literal.one...Literal.nine: - state = .PreDecimalDigits + state = .preDecimalDigits default: - throw JSONParser.Error.NumberSymbolMissingDigits(offset: start) + throw JSONParser.Error.numberSymbolMissingDigits(offset: start) } } mutating func parseLeadingZero() { - assert(state == .LeadingZero, "Unexpected state entering parseLeadingZero") + assert(state == .leadingZero, "Unexpected state entering parseLeadingZero") - loc = loc.successor() + loc = (loc + 1) guard loc < input.count else { - state = .Done + state = .done return } switch input[loc] { case Literal.PERIOD: - state = .Decimal + state = .decimal case Literal.e, Literal.E: - state = .Exponent + state = .exponent default: - state = .Done + state = .done } } - mutating func parsePreDecimalDigits(@noescape f: (UInt8) throws -> Void) rethrows { - assert(state == .PreDecimalDigits, "Unexpected state entering parsePreDecimalDigits") + mutating func parsePreDecimalDigits(f: (UInt8) throws -> Void) rethrows { + assert(state == .preDecimalDigits, "Unexpected state entering parsePreDecimalDigits") advancing: while loc < input.count { let c = input[loc] switch c { case Literal.zero...Literal.nine: try f(c) - loc = loc.successor() + loc = (loc + 1) case Literal.PERIOD: - state = .Decimal + state = .decimal return case Literal.e, Literal.E: - state = .Exponent + state = .exponent return default: @@ -697,37 +689,37 @@ private struct NumberParser { } } - state = .Done + state = .done } mutating func parseDecimal() throws { - assert(state == .Decimal, "Unexpected state entering parseDecimal") - loc = loc.successor() + assert(state == .decimal, "Unexpected state entering parseDecimal") + loc = (loc + 1) guard loc < input.count else { - throw JSONParser.Error.EndOfStreamUnexpected + throw JSONParser.Error.endOfStreamUnexpected } switch input[loc] { case Literal.zero...Literal.nine: - state = .PostDecimalDigits + state = .postDecimalDigits default: - throw JSONParser.Error.NumberMissingFractionalDigits(offset: start) + throw JSONParser.Error.numberMissingFractionalDigits(offset: start) } } - mutating func parsePostDecimalDigits(@noescape f: (UInt8) throws -> Void) rethrows { - assert(state == .PostDecimalDigits, "Unexpected state entering parsePostDecimalDigits") + mutating func parsePostDecimalDigits(f: (UInt8) throws -> Void) rethrows { + assert(state == .postDecimalDigits, "Unexpected state entering parsePostDecimalDigits") advancing: while loc < input.count { let c = input[loc] switch c { case Literal.zero...Literal.nine: try f(c) - loc = loc.successor() + loc = (loc + 1) case Literal.e, Literal.E: - state = .Exponent + state = .exponent return default: @@ -735,104 +727,119 @@ private struct NumberParser { } } - state = .Done + state = .done } mutating func parseExponent() throws -> JSONParser.Sign { - assert(state == .Exponent, "Unexpected state entering parseExponent") + assert(state == .exponent, "Unexpected state entering parseExponent") - loc = loc.successor() + loc = (loc + 1) guard loc < input.count else { - throw JSONParser.Error.EndOfStreamUnexpected + throw JSONParser.Error.endOfStreamUnexpected } switch input[loc] { case Literal.zero...Literal.nine: - state = .ExponentDigits + state = .exponentDigits case Literal.PLUS: - state = .ExponentSign + state = .exponentSign case Literal.MINUS: - state = .ExponentSign - return .Negative + state = .exponentSign + return .negative default: - throw JSONParser.Error.NumberSymbolMissingDigits(offset: start) + throw JSONParser.Error.numberSymbolMissingDigits(offset: start) } - return .Positive + return .positive } mutating func parseExponentSign() throws { - assert(state == .ExponentSign, "Unexpected state entering parseExponentSign") - loc = loc.successor() + assert(state == .exponentSign, "Unexpected state entering parseExponentSign") + loc = (loc + 1) guard loc < input.count else { - throw JSONParser.Error.EndOfStreamUnexpected + throw JSONParser.Error.endOfStreamUnexpected } switch input[loc] { case Literal.zero...Literal.nine: - state = .ExponentDigits + state = .exponentDigits default: - throw JSONParser.Error.NumberSymbolMissingDigits(offset: start) + throw JSONParser.Error.numberSymbolMissingDigits(offset: start) } } - mutating func parseExponentDigits(@noescape f: (UInt8) throws -> Void) rethrows { - assert(state == .ExponentDigits, "Unexpected state entering parseExponentDigits") + mutating func parseExponentDigits(f: (UInt8) throws -> Void) rethrows { + assert(state == .exponentDigits, "Unexpected state entering parseExponentDigits") advancing: while loc < input.count { let c = input[loc] switch c { case Literal.zero...Literal.nine: try f(c) - loc = loc.successor() + loc = (loc + 1) default: break advancing } } - state = .Done + state = .done } } public extension JSONParser { - /// Creates a `JSONParser` ready to parse UTF-8 encoded `NSData`. + /// Creates a `JSONParser` ready to parse UTF-8 encoded `Data`. /// /// If the data is mutable, it is copied before parsing. The data's lifetime /// is extended for the duration of parsing. - init(utf8Data inData: NSData) { - let data = inData.copy() as! NSData - let buffer = UnsafeBufferPointer(start: UnsafePointer(data.bytes), count: data.length) - self.init(buffer: buffer, owner: data) + @available(*, unavailable, message: "Replaced with parse(utf8:)") + init(utf8Data inData: Data) { + fatalError("unavailable code cannot be executed") } /// Creates a `JSONParser` from the code units represented by the `string`. /// /// The synthesized string is lifetime-extended for the duration of parsing. + @available(*, unavailable, message: "Replaced with parse(utf8:)") init(string: String) { - let codePoints = string.nulTerminatedUTF8 - let buffer = codePoints.withUnsafeBufferPointer { nulTerminatedBuffer in - // don't want to include the nul termination in the buffer - trim it off - UnsafeBufferPointer(start: nulTerminatedBuffer.baseAddress, count: nulTerminatedBuffer.count - 1) + fatalError("unavailable code cannot be executed") + } + + /// Creates an instance of `JSON` from UTF-8 encoded `data`. + static func parse(utf8 data: Data) throws -> JSON { + return try data.withUnsafeBytes { (ptr: UnsafePointer) -> JSON in + let buffer = UnsafeBufferPointer(start: ptr, count: data.count) + var parser = JSONParser(input: buffer) + return try parser.parse() + } + } + + /// Creates an instance of `JSON` from `string`. + static func parse(_ string: String) throws -> JSON { + return try string.utf8CString.withUnsafeBufferPointer { (nulTerminatedBuffer) throws -> JSON in + return try nulTerminatedBuffer.baseAddress!.withMemoryRebound(to: UInt8.self, capacity: nulTerminatedBuffer.count) { (utf8Base) throws -> JSON in + // don't want to include the nul termination in the buffer - trim it off + let buffer = UnsafeBufferPointer(start: utf8Base, count: nulTerminatedBuffer.count - 1) + var parser = JSONParser(input: buffer) + return try parser.parse() + } } - self.init(buffer: buffer, owner: codePoints) } } extension JSONParser: JSONParserType { - /// Creates an instance of `JSON` from UTF-8 encoded `NSData`. - /// - parameter data: An instance of `NSData` to parse `JSON` from. + /// Creates an instance of `JSON` from UTF-8 encoded `Data`. + /// - parameter data: An instance of `Data` to parse `JSON` from. /// - throws: Any `JSONParser.Error` that arises during decoding. /// - seealso: JSONParser.parse() - public static func createJSONFromData(data: NSData) throws -> JSON { - var parser = JSONParser(utf8Data: data) - return try parser.parse() + public static func createJSON(from data: Data) throws -> JSON { + return try parse(utf8: data) } } @@ -845,67 +852,67 @@ extension JSONParser { /// document. Most errors include an associated `offset`, representing the /// offset into the UTF-8 characters making up the document where the error /// occurred. - public enum Error: ErrorType { + public enum Error: Swift.Error { /// The parser ran out of data prematurely. This usually means a value /// was not escaped, such as a string literal not ending with a double /// quote. - case EndOfStreamUnexpected + case endOfStreamUnexpected /// Unexpected non-whitespace data was left around `offset` after /// parsing all valid JSON. - case EndOfStreamGarbage(offset: Int) + case endOfStreamGarbage(offset: Int) /// Too many nested objects or arrays occured at the literal started /// around `offset`. - case ExceededNestingLimit(offset: Int) + case exceededNestingLimit(offset: Int) /// A `character` was not a valid start of a value around `offset`. - case ValueInvalid(offset: Int, character: UnicodeScalar) + case valueInvalid(offset: Int, character: UnicodeScalar) /// Badly-formed Unicode escape sequence at `offset`. A Unicode escape /// uses the text "\u" followed by 4 hex digits, such as "\uF09F\uA684" /// to represent U+1F984, "UNICORN FACE". - case UnicodeEscapeInvalid(offset: Int) + case unicodeEscapeInvalid(offset: Int) /// Badly-formed control character around `offset`. JSON supports /// backslash-escaped double quotes, slashes, whitespace control codes, /// and Unicode escape sequences. - case ControlCharacterUnrecognized(offset: Int) + case controlCharacterUnrecognized(offset: Int) /// Invalid token, expected `null` around `offset` - case LiteralNilMisspelled(offset: Int) + case literalNilMisspelled(offset: Int) /// Invalid token, expected `true` around `offset` - case LiteralTrueMisspelled(offset: Int) + case literalTrueMisspelled(offset: Int) /// Invalid token, expected `false` around `offset` - case LiteralFalseMisspelled(offset: Int) + case literalFalseMisspelled(offset: Int) /// Badly-formed collection at given `offset`, expected `,` or `:` - case CollectionMissingSeparator(offset: Int) + case collectionMissingSeparator(offset: Int) /// While parsing an object literal, a value was found without a key /// around `offset`. The start of a string literal was expected. - case DictionaryMissingKey(offset: Int) + case dictionaryMissingKey(offset: Int) /// Badly-formed number with no digits around `offset`. After a decimal /// point, a number must include some number of digits. - case NumberMissingFractionalDigits(offset: Int) + case numberMissingFractionalDigits(offset: Int) /// Badly-formed number with symbols ("-" or "e") but no following /// digits around `offset`. - case NumberSymbolMissingDigits(offset: Int) + case numberSymbolMissingDigits(offset: Int) /// Supplied data is encoded in an unsupported format. - case InvalidUnicodeStreamEncoding(detectedEncoding: JSONEncodingDetector.Encoding) + case invalidUnicodeStreamEncoding(detectedEncoding: JSONEncodingDetector.Encoding) } - private enum InternalError: ErrorType { + fileprivate enum InternalError: Swift.Error { /// Attempted to parse an integer outside the range of [Int.min, Int.max] /// or a double outside the range of representable doubles. Note that /// for doubles, this could be an overflow or an underflow - we don't /// get enough information from Swift here to know which it is. The number /// causing the overflow/underflow began at `offset`. - case NumberOverflow(offset: Int) + case numberOverflow(offset: Int) } } diff --git a/Sources/JSONParsing.swift b/Sources/JSONParsing.swift index 90cb6be2..bd8d5b4a 100644 --- a/Sources/JSONParsing.swift +++ b/Sources/JSONParsing.swift @@ -10,14 +10,14 @@ import Foundation // MARK: - Deserialize JSON -/// Protocol describing a backend parser that can produce `JSON` from `NSData`. +/// Protocol describing a backend parser that can produce `JSON` from `Data`. public protocol JSONParserType { - /// Creates an instance of `JSON` from `NSData`. - /// - parameter data: An instance of `NSData` to use to create `JSON`. + /// Creates an instance of `JSON` from `Data`. + /// - parameter data: An instance of `Data` to use to create `JSON`. /// - throws: An error that may arise from calling `JSONObjectWithData(_:options:)` on `NSJSONSerialization` with the given data. /// - returns: An instance of `JSON`. - static func createJSONFromData(data: NSData) throws -> JSON + static func createJSON(from data: Data) throws -> JSON } @@ -25,47 +25,47 @@ extension JSON { /// Create `JSON` from UTF-8 `data`. By default, parses using the /// Swift-native `JSONParser` backend. - public init(data: NSData, usingParser parser: JSONParserType.Type = JSONParser.self) throws { - self = try parser.createJSONFromData(data) + public init(data: Data, usingParser parser: JSONParserType.Type = JSONParser.self) throws { + self = try parser.createJSON(from: data) } /// Create `JSON` from UTF-8 `string`. public init(jsonString: Swift.String, usingParser parser: JSONParserType.Type = JSONParser.self) throws { - self = try parser.createJSONFromData((jsonString as NSString).dataUsingEncoding(NSUTF8StringEncoding) ?? NSData()) + self = try parser.createJSON(from: (jsonString as NSString).data(using: Swift.String.Encoding.utf8.rawValue) ?? Data()) } } // MARK: - NSJSONSerialization -extension NSJSONSerialization: JSONParserType { +extension JSONSerialization: JSONParserType { - // MARK: Decode NSData + // MARK: Decode Data /// Use the built-in, Objective-C based JSON parser to create `JSON`. - /// - parameter data: An instance of `NSData`. + /// - parameter data: An instance of `Data`. /// - returns: An instance of `JSON`. - /// - throws: An error that may arise if the `NSData` cannot be parsed into an object. - public static func createJSONFromData(data: NSData) throws -> JSON { - return makeJSON(try NSJSONSerialization.JSONObjectWithData(data, options: [])) + /// - throws: An error that may arise if the `Data` cannot be parsed into an object. + public static func createJSON(from data: Data) throws -> JSON { + return makeJSON(with: try JSONSerialization.jsonObject(with: data, options: [])) } // MARK: Make JSON /// Makes a `JSON` object by matching its argument to a case in the `JSON` enum. - /// - parameter object: The instance of `AnyObject` returned from serializing the JSON. + /// - parameter object: The instance of `Any` returned from serializing the JSON. /// - returns: An instance of `JSON` matching the JSON given to the function. - private static func makeJSON(object: AnyObject) -> JSON { + private static func makeJSON(with object: Any) -> JSON { switch object { case let n as NSNumber: let numberType = CFNumberGetType(n) switch numberType { - case .CharType: - return .Bool(n.boolValue) + case .charType: + return .bool(n.boolValue) - case .ShortType, .IntType, .LongType, .CFIndexType, .NSIntegerType, .SInt8Type, .SInt16Type, .SInt32Type: - return .Int(n.integerValue) + case .shortType, .intType, .longType, .cfIndexType, .nsIntegerType, .sInt8Type, .sInt16Type, .sInt32Type: + return .int(n.intValue) - case .SInt64Type, .LongLongType /* overflows 32-bit Int */: + case .sInt64Type, .longLongType /* overflows 32-bit Int */: #if /* 32-bit arch */ arch(arm) || arch(i386) // Why double, when the Freddy parser would bump to String? // @@ -80,26 +80,26 @@ extension NSJSONSerialization: JSONParserType { // you'll have to switch from .double to .string for pulling out // overflowing values, but if you stick with a single parser, // you at least won't have architecture-dependent lookups! - return .Double(n.doubleValue) + return .double(n.doubleValue) #else - return .Int(n.integerValue) + return .int(n.intValue) #endif - case .Float32Type, .Float64Type, .FloatType, .DoubleType, .CGFloatType: - return .Double(n.doubleValue) + case .float32Type, .float64Type, .floatType, .doubleType, .cgFloatType: + return .double(n.doubleValue) } - case let arr as [AnyObject]: + case let arr as [Any]: return makeJSONArray(arr) - case let dict as [Swift.String: AnyObject]: + case let dict as [Swift.String: Any]: return makeJSONDictionary(dict) case let s as Swift.String: - return .String(s) + return .string(s) default: - return .Null + return .null } } @@ -108,8 +108,8 @@ extension NSJSONSerialization: JSONParserType { /// Makes a `JSON` array from the object passed in. /// - parameter jsonArray: The array to transform into a `JSON`. /// - returns: An instance of `JSON` matching the array. - private static func makeJSONArray(jsonArray: [AnyObject]) -> JSON { - return .Array(jsonArray.map(makeJSON)) + private static func makeJSONArray(_ jsonArray: [Any]) -> JSON { + return .array(jsonArray.map(makeJSON)) } // MARK: Make a JSON Dictionary @@ -117,9 +117,9 @@ extension NSJSONSerialization: JSONParserType { /// Makes a `JSON` dictionary from the Cocoa dictionary passed in. /// - parameter jsonDict: The dictionary to transform into `JSON`. /// - returns: An instance of `JSON` matching the dictionary. - private static func makeJSONDictionary(jsonDict: [Swift.String: AnyObject]) -> JSON { + private static func makeJSONDictionary(_ jsonDict: [Swift.String: Any]) -> JSON { return JSON(jsonDict.lazy.map { (key, value) in - (key, makeJSON(value)) + (key, makeJSON(with: value)) }) } diff --git a/Sources/JSONSerializing.swift b/Sources/JSONSerializing.swift index 649b9454..85a6f713 100644 --- a/Sources/JSONSerializing.swift +++ b/Sources/JSONSerializing.swift @@ -6,48 +6,47 @@ import Foundation extension JSON { - /// Attempt to serialize `JSON` into an `NSData`. + /// Attempt to serialize `JSON` into an `Data`. /// - returns: A byte-stream containing the `JSON` ready for wire transfer. - /// - throws: Errors that arise from `NSJSONSerialization`. - /// - see: Foundation.NSJSONSerialization - public func serialize() throws -> NSData { - let obj: AnyObject = toNSJSONSerializationObject() - return try NSJSONSerialization.dataWithJSONObject(obj, options: []) + /// - throws: Errors that arise from `JSONSerialization`. + /// - see: Foundation.JSONSerialization + public func serialize() throws -> Data { + return try JSONSerialization.data(withJSONObject: toJSONSerializationValue(), options: []) } /// Attempt to serialize `JSON` into a `String`. /// - returns: A `String` containing the `JSON`. - /// - throws: A `JSON.Error.StringSerializationError` or errors that arise from `NSJSONSerialization`. - /// - see: Foundation.NSJSONSerialization - public func serializeString() throws -> Swift.String { + /// - throws: A `JSON.Error.StringSerializationError` or errors that arise from `JSONSerialization`. + /// - see: Foundation.JSONSerialization + public func serializeString() throws -> String { let data = try self.serialize() - guard let json = Swift.String(data: data, encoding: NSUTF8StringEncoding) else { - throw Error.StringSerializationError + guard let json = String(data: data, encoding: String.Encoding.utf8) else { + throw Error.stringSerializationError } return json } /// A function to help with the serialization of `JSON`. - /// - returns: An `AnyObject` suitable for `NSJSONSerialization`'s use. - private func toNSJSONSerializationObject() -> AnyObject { + /// - returns: An `Any` suitable for `JSONSerialization`'s use. + private func toJSONSerializationValue() -> Any { switch self { - case .Array(let jsonArray): - return jsonArray.map { $0.toNSJSONSerializationObject() } - case .Dictionary(let jsonDictionary): - var cocoaDictionary = Swift.Dictionary(minimumCapacity: jsonDictionary.count) + case .array(let jsonArray): + return jsonArray.map { $0.toJSONSerializationValue() } + case .dictionary(let jsonDictionary): + var cocoaDictionary = Swift.Dictionary(minimumCapacity: jsonDictionary.count) for (key, json) in jsonDictionary { - cocoaDictionary[key] = json.toNSJSONSerializationObject() + cocoaDictionary[key] = json.toJSONSerializationValue() } return cocoaDictionary - case .String(let str): + case .string(let str): return str - case .Double(let num): - return num - case .Int(let int): - return int - case .Bool(let b): - return b - case .Null: + case .double(let num): + return NSNumber(value: num) + case .int(let int): + return NSNumber(value: int) + case .bool(let b): + return NSNumber(value: b) + case .null: return NSNull() } diff --git a/Sources/JSONSubscripting.swift b/Sources/JSONSubscripting.swift index b6860caf..6d1bd3ef 100644 --- a/Sources/JSONSubscripting.swift +++ b/Sources/JSONSubscripting.swift @@ -19,29 +19,29 @@ public protocol JSONPathType { /// an error rather than convert to `nil`. /// /// Upon failure, implementers should throw an error from `JSON.Error`. - func valueInDictionary(dictionary: [Swift.String : JSON]) throws -> JSON + func value(in dictionary: [String : JSON]) throws -> JSON /// Use `self` to index into an `array`. /// - /// Unlike Swift array, attempting to index outside the collection's bounds + /// Unlike Swift arrays, attempting to index outside the collection's bounds /// should throw an error rather than crash. /// /// Upon failure, implementers should throw an error from `JSON.Error`. - func valueInArray(array: [JSON]) throws -> JSON + func value(in array: [JSON]) throws -> JSON } extension JSONPathType { /// The default behavior for keying into a dictionary is to throw /// `JSON.Error.UnexpectedSubscript`. - public func valueInDictionary(dictionary: [Swift.String : JSON]) throws -> JSON { - throw JSON.Error.UnexpectedSubscript(type: Self.self) + public func value(in dictionary: [String : JSON]) throws -> JSON { + throw JSON.Error.unexpectedSubscript(type: Self.self) } /// The default behavior for indexing into an array is to throw /// `JSON.Error.UnexpectedSubscript`. - public func valueInArray(array: [JSON]) throws -> JSON { - throw JSON.Error.UnexpectedSubscript(type: Self.self) + public func value(in array: [JSON]) throws -> JSON { + throw JSON.Error.unexpectedSubscript(type: Self.self) } } @@ -53,9 +53,9 @@ extension String: JSONPathType { /// - throws: `.KeyNotFound` with an associated value of `self`, where `self` is a `String`, /// should the key not be present within the `JSON`. /// - returns: The `JSON` value associated with the given key. - public func valueInDictionary(dictionary: [Swift.String : JSON]) throws -> JSON { + public func value(in dictionary: [String : JSON]) throws -> JSON { guard let next = dictionary[self] else { - throw JSON.Error.KeyNotFound(key: self) + throw JSON.Error.keyNotFound(key: self) } return next } @@ -69,9 +69,9 @@ extension Int: JSONPathType { /// - throws: `.IndexOutOfBounds` with an associated value of `self`, where `self` is an `Int`, /// should the index not be within the valid range for the array of `JSON`. /// - returns: The `JSON` value found at the given index. - public func valueInArray(array: [JSON]) throws -> JSON { + public func value(in array: [JSON]) throws -> JSON { guard case array.indices = self else { - throw JSON.Error.IndexOutOfBounds(index: self) + throw JSON.Error.indexOutOfBounds(index: self) } return array[self] } @@ -82,27 +82,27 @@ extension Int: JSONPathType { private extension JSON { - enum SubscriptError: ErrorType { - case SubscriptIntoNull(JSONPathType) + enum SubscriptError: Swift.Error { + case subscriptIntoNull(JSONPathType) } - func valueForPathFragment(fragment: JSONPathType, detectNull: Swift.Bool) throws -> JSON { + func value(for pathFragment: JSONPathType, detectingNull: Bool) throws -> JSON { switch self { - case .Null where detectNull: - throw SubscriptError.SubscriptIntoNull(fragment) - case let .Dictionary(dict): - return try fragment.valueInDictionary(dict) - case let .Array(array): - return try fragment.valueInArray(array) + case .null where detectingNull: + throw SubscriptError.subscriptIntoNull(pathFragment) + case let .dictionary(dict): + return try pathFragment.value(in: dict) + case let .array(array): + return try pathFragment.value(in: array) default: - throw Error.UnexpectedSubscript(type: fragment.dynamicType) + throw Error.unexpectedSubscript(type: type(of: pathFragment)) } } - func valueAtPath(path: [JSONPathType], detectNull: Swift.Bool = false) throws -> JSON { + func value(at path: [JSONPathType], detectingNull: Bool = false) throws -> JSON { var result = self - for fragment in path { - result = try result.valueForPathFragment(fragment, detectNull: detectNull) + for pathFragment in path { + result = try result.value(for: pathFragment, detectingNull: detectingNull) } return result } @@ -113,12 +113,12 @@ private extension JSON { extension JSON { - public subscript(key: Swift.String) -> JSON? { - return try? valueForPathFragment(key, detectNull: false) + public subscript(key: String) -> JSON? { + return try? value(for: key, detectingNull: false) } - public subscript(index: Swift.Int) -> JSON? { - return try? valueForPathFragment(index, detectNull: false) + public subscript(index: Int) -> JSON? { + return try? value(for: index, detectingNull: false) } } @@ -142,53 +142,53 @@ extension JSON { /// corresponding `JSON` value. /// * `TypeNotConvertible`: The target value's type inside of /// the `JSON` instance does not match `Decoded`. - public func decode(path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> Decoded { - return try Decoded(json: valueAtPath(path)) + public func decode(at path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> Decoded { + return try Decoded(json: value(at: path)) } /// Retrieves a `Double` from a path into JSON. /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON` /// - returns: A floating-point `Double` - /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`. - /// - seealso: `JSON.decode(_:type:)` - public func double(path: JSONPathType...) throws -> Swift.Double { - return try Swift.Double(json: valueAtPath(path)) + /// - throws: One of the `JSON.Error` cases thrown by `decode(at:type:)`. + /// - seealso: `JSON.decode(at:type:)` + public func getDouble(at path: JSONPathType...) throws -> Double { + return try Double(json: value(at: path)) } /// Retrieves an `Int` from a path into JSON. /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON` /// - returns: A numeric `Int` - /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`. - /// - seealso: `JSON.decode(_:type:)` - public func int(path: JSONPathType...) throws -> Swift.Int { - return try Swift.Int(json: valueAtPath(path)) + /// - throws: One of the `JSON.Error` cases thrown by `decode(at:type:)`. + /// - seealso: `JSON.decode(at:type:)` + public func getInt(at path: JSONPathType...) throws -> Int { + return try Int(json: value(at: path)) } /// Retrieves a `String` from a path into JSON. /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON` /// - returns: A textual `String` - /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`. - /// - seealso: `JSON.decode(_:type:)` - public func string(path: JSONPathType...) throws -> Swift.String { - return try Swift.String(json: valueAtPath(path)) + /// - throws: One of the `JSON.Error` cases thrown by `decode(at:type:)`. + /// - seealso: `JSON.decode(at:type:)` + public func getString(at path: JSONPathType...) throws -> String { + return try String(json: value(at: path)) } /// Retrieves a `Bool` from a path into JSON. /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON` /// - returns: A truthy `Bool` - /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`. - /// - seealso: `JSON.decode(_:type:)` - public func bool(path: JSONPathType...) throws -> Swift.Bool { - return try Swift.Bool(json: valueAtPath(path)) + /// - throws: One of the `JSON.Error` cases thrown by `decode(at:type:)`. + /// - seealso: `JSON.decode(at:type:)` + public func getBool(at path: JSONPathType...) throws -> Bool { + return try Bool(json: value(at: path)) } /// Retrieves a `[JSON]` from a path into JSON. /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON` /// - returns: An `Array` of `JSON` elements - /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`. - /// - seealso: `JSON.decode(_:type:)` - public func array(path: JSONPathType...) throws -> [JSON] { - return try JSON.getArray(valueAtPath(path)) + /// - throws: One of the `JSON.Error` cases thrown by `decode(at:type:)`. + /// - seealso: `JSON.decode(at:type:)` + public func getArray(at path: JSONPathType...) throws -> [JSON] { + return try JSON.getArray(from: value(at: path)) } /// Attempts to decode many values from a descendant JSON array at a path @@ -198,20 +198,20 @@ extension JSON { /// make the return type clear, pass a type implementing `JSONDecodable` /// to disambiguate the type to decode with. /// - returns: An `Array` of decoded elements - /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`, or + /// - throws: One of the `JSON.Error` cases thrown by `decode(at:type:)`, or /// any error that arises from decoding the contained values. - /// - seealso: `JSON.decode(_:type:)` - public func arrayOf(path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> [Decoded] { - return try JSON.getArrayOf(valueAtPath(path)) + /// - seealso: `JSON.decode(at:type:)` + public func decodedArray(at path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> [Decoded] { + return try JSON.decodedArray(from: value(at: path)) } /// Retrieves a `[String: JSON]` from a path into JSON. /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON` /// - returns: An `Dictionary` of `String` mapping to `JSON` elements - /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`. - /// - seealso: `JSON.decode(_:type:)` - public func dictionary(path: JSONPathType...) throws -> [Swift.String: JSON] { - return try JSON.getDictionary(valueAtPath(path)) + /// - throws: One of the `JSON.Error` cases thrown by `decode(at:type:)`. + /// - seealso: `JSON.decode(at:type:)` + public func getDictionary(at path: JSONPathType...) throws -> [String: JSON] { + return try JSON.getDictionary(from: value(at: path)) } /// Attempts to decode many values from a descendant JSON object at a path @@ -221,11 +221,11 @@ extension JSON { /// make the return type clear, pass a type implementing `JSONDecodable` /// to disambiguate the value type to decode with. /// - returns: A `Dictionary` of `String` keys and decoded values. - /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)` or + /// - throws: One of the `JSON.Error` cases thrown by `decode(at:type:)` or /// any error that arises from decoding the contained values. - /// - seealso: `JSON.decode(_:type:)` - public func dictionaryOf(path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> [Swift.String: Decoded] { - return try JSON.getDictionaryOf(valueAtPath(path)) + /// - seealso: `JSON.decode(at:type:)` + public func decodedDictionary(at path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> [String: Decoded] { + return try JSON.decodedDictionary(from: value(at: path)) } } @@ -237,9 +237,9 @@ extension JSON { /// An `OptionSetType` used to represent the different options available for subscripting `JSON` with `null` values or missing keys. /// * `.NullBecomesNil` - Treat `null` values as `nil`. /// * `.MissingKeyBecomesNil` - Treat missing keys as `nil`. - public struct SubscriptingOptions: OptionSetType { - public let rawValue: Swift.Int - public init(rawValue: Swift.Int) { + public struct SubscriptingOptions: OptionSet { + public let rawValue: Int + public init(rawValue: Int) { self.rawValue = rawValue } @@ -249,20 +249,20 @@ extension JSON { public static let MissingKeyBecomesNil = SubscriptingOptions(rawValue: 1 << 1) } - private func mapOptionalAtPath(path: [JSONPathType], alongPath: SubscriptingOptions, @noescape transform: JSON throws -> Value) throws -> Value? { - let detectNull = alongPath.contains(.NullBecomesNil) - let detectNotFound = alongPath.contains(.MissingKeyBecomesNil) + fileprivate func mapOptional(at path: [JSONPathType], alongPath options: SubscriptingOptions, transform: (JSON) throws -> Value) throws -> Value? { + let detectNull = options.contains(.NullBecomesNil) + let detectNotFound = options.contains(.MissingKeyBecomesNil) var json: JSON? do { - json = try valueAtPath(path, detectNull: detectNull) + json = try value(at: path, detectingNull: detectNull) return try json.map(transform) - } catch Error.IndexOutOfBounds where detectNotFound { + } catch Error.indexOutOfBounds where detectNotFound { return nil - } catch Error.KeyNotFound where detectNotFound { + } catch Error.keyNotFound where detectNotFound { return nil - } catch Error.ValueNotConvertible where detectNull && json == .Null { + } catch Error.valueNotConvertible where detectNull && json == .null { return nil - } catch SubscriptError.SubscriptIntoNull where detectNull { + } catch SubscriptError.subscriptIntoNull where detectNull { return nil } } @@ -275,8 +275,8 @@ extension JSON { /// - returns: An instance of some type that conforms to `JSONDecodable`. /// - throws: `Error.ValueNotConvertible` if the `JSON` instance is `.Null`. private static func getDecoded(json: JSON) throws -> Decoded { - guard json != .Null else { - throw Error.ValueNotConvertible(value: json, to: Decoded.self) + guard json != .null else { + throw Error.valueNotConvertible(value: json, to: Decoded.self) } return try Decoded.init(json: json) } @@ -298,8 +298,8 @@ extension JSON { /// * `TypeNotConvertible`: The target value's type inside of the `JSON` /// instance does not match the decoded value. /// * Any error that arises from decoding the value. - public func decode(path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> Decoded? { - return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getDecoded) + public func decode(at path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> Decoded? { + return try mapOptional(at: path, alongPath: options, transform: JSON.getDecoded) } /// Optionally retrieves a `Double` from a path into JSON. @@ -315,8 +315,8 @@ extension JSON { /// corresponding `JSON` value. /// * `TypeNotConvertible`: The target value's type inside of the `JSON` /// instance does not match the decoded value. - public func double(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Swift.Double? { - return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Double.init) + public func getDouble(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Double? { + return try mapOptional(at: path, alongPath: options, transform: Double.init) } /// Optionally retrieves a `Int` from a path into JSON. @@ -332,8 +332,8 @@ extension JSON { /// corresponding `JSON` value. /// * `TypeNotConvertible`: The target value's type inside of the `JSON` /// instance does not match the decoded value. - public func int(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Swift.Int? { - return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Int.init) + public func getInt(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Int? { + return try mapOptional(at: path, alongPath: options, transform: Int.init) } /// Optionally retrieves a `String` from a path into JSON. @@ -349,8 +349,8 @@ extension JSON { /// corresponding `JSON` value. /// * `TypeNotConvertible`: The target value's type inside of the `JSON` /// instance does not match the decoded value. - public func string(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Swift.String? { - return try mapOptionalAtPath(path, alongPath: options, transform: Swift.String.init) + public func getString(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> String? { + return try mapOptional(at: path, alongPath: options, transform: String.init) } /// Optionally retrieves a `Bool` from a path into JSON. @@ -366,8 +366,8 @@ extension JSON { /// corresponding `JSON` value. /// * `TypeNotConvertible`: The target value's type inside of the `JSON` /// instance does not match the decoded value. - public func bool(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Swift.Bool? { - return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Bool.init) + public func getBool(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Bool? { + return try mapOptional(at: path, alongPath: options, transform: Bool.init) } /// Optionally retrieves a `[JSON]` from a path into the recieving structure. @@ -384,8 +384,8 @@ extension JSON { /// corresponding `JSON` value. /// * `TypeNotConvertible`: The target value's type inside of the `JSON` /// instance does not match the decoded value. - public func array(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> [JSON]? { - return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArray) + public func getArray(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> [JSON]? { + return try mapOptional(at: path, alongPath: options, transform: JSON.getArray) } /// Optionally decodes many values from a descendant array at a path into @@ -406,8 +406,8 @@ extension JSON { /// * `TypeNotConvertible`: The target value's type inside of the `JSON` /// instance does not match the decoded value. /// * Any error that arises from decoding the value. - public func arrayOf(path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> [Decoded]? { - return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArrayOf) + public func decodedArray(at path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> [Decoded]? { + return try mapOptional(at: path, alongPath: options, transform: JSON.decodedArray) } /// Optionally retrieves a `[String: JSON]` from a path into the recieving @@ -425,8 +425,8 @@ extension JSON { /// corresponding `JSON` value. /// * `TypeNotConvertible`: The target value's type inside of the `JSON` /// instance does not match the decoded value. - public func dictionary(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> [Swift.String: JSON]? { - return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getDictionary) + public func getDictionary(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> [String: JSON]? { + return try mapOptional(at: path, alongPath: options, transform: JSON.getDictionary) } /// Optionally attempts to decode many values from a descendant object at a path @@ -448,8 +448,8 @@ extension JSON { /// * `TypeNotConvertible`: The target value's type inside of the `JSON` /// instance does not match the decoded value. /// * Any error that arises from decoding the value. - public func dictionaryOf(path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> [Swift.String: Decoded]? { - return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getDictionaryOf) + public func decodedDictionary(at path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> [String: Decoded]? { + return try mapOptional(at: path, alongPath: options, transform: JSON.decodedDictionary) } } @@ -458,8 +458,8 @@ extension JSON { extension JSON { - private func mapOptionalAtPath(path: [JSONPathType], @noescape fallback: () -> Value, @noescape transform: JSON throws -> Value) throws -> Value { - return try mapOptionalAtPath(path, alongPath: .MissingKeyBecomesNil, transform: transform) ?? fallback() + fileprivate func mapOptional(at path: [JSONPathType], fallback: () -> Value, transform: (JSON) throws -> Value) throws -> Value { + return try mapOptional(at: path, alongPath: .MissingKeyBecomesNil, transform: transform) ?? fallback() } /// Attempts to decode into the returning type from a path into @@ -472,18 +472,17 @@ extension JSON { /// corresponding `JSON` value. /// * `TypeNotConvertible`: The target value's type inside of /// the `JSON` instance does not match `Decoded`. - public func decode(path: JSONPathType..., @autoclosure or fallback: () -> Decoded) throws -> Decoded { - return try mapOptionalAtPath(path, fallback: fallback, transform: Decoded.init) + public func decode(at path: JSONPathType..., or fallback: @autoclosure() -> Decoded) throws -> Decoded { + return try mapOptional(at: path, fallback: fallback, transform: Decoded.init) } /// Retrieves a `Double` from a path into JSON or a fallback if not found. /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON` /// - parameter fallback: `Double` to use when one is missing at the subscript. /// - returns: A floating-point `Double` - /// - throws: One of the `JSON.Error` cases thrown by calling `mapOptionalAtPath(_:fallback:transform:)`. - /// - seealso: `optionalAtPath(_:ifNotFound)`. - public func double(path: JSONPathType..., @autoclosure or fallback: () -> Swift.Double) throws -> Swift.Double { - return try mapOptionalAtPath(path, fallback: fallback, transform: Swift.Double.init) + /// - throws: One of the `JSON.Error` cases thrown by calling `mapOptional(at:fallback:transform:)`. + public func getDouble(at path: JSONPathType..., or fallback: @autoclosure() -> Double) throws -> Double { + return try mapOptional(at: path, fallback: fallback, transform: Double.init) } /// Retrieves an `Int` from a path into JSON or a fallback if not found. @@ -499,8 +498,8 @@ extension JSON { /// corresponding `JSON` value. /// * `TypeNotConvertible`: The target value's type inside of the `JSON` /// instance does not match the decoded value. - public func int(path: JSONPathType..., @autoclosure or fallback: () -> Swift.Int) throws -> Swift.Int { - return try mapOptionalAtPath(path, fallback: fallback, transform: Swift.Int.init) + public func getInt(at path: JSONPathType..., or fallback: @autoclosure() -> Int) throws -> Int { + return try mapOptional(at: path, fallback: fallback, transform: Int.init) } /// Retrieves a `String` from a path into JSON or a fallback if not found. @@ -516,8 +515,8 @@ extension JSON { /// corresponding `JSON` value. /// * `TypeNotConvertible`: The target value's type inside of the `JSON` /// instance does not match the decoded value. - public func string(path: JSONPathType..., @autoclosure or fallback: () -> Swift.String) throws -> Swift.String { - return try mapOptionalAtPath(path, fallback: fallback, transform: Swift.String.init) + public func getString(at path: JSONPathType..., or fallback: @autoclosure() -> String) throws -> String { + return try mapOptional(at: path, fallback: fallback, transform: String.init) } /// Retrieves a `Bool` from a path into JSON or a fallback if not found. @@ -533,8 +532,8 @@ extension JSON { /// corresponding `JSON` value. /// * `TypeNotConvertible`: The target value's type inside of the `JSON` /// instance does not match the decoded value. - public func bool(path: JSONPathType..., @autoclosure or fallback: () -> Swift.Bool) throws -> Swift.Bool { - return try mapOptionalAtPath(path, fallback: fallback, transform: Swift.Bool.init) + public func getBool(at path: JSONPathType..., or fallback: @autoclosure() -> Bool) throws -> Bool { + return try mapOptional(at: path, fallback: fallback, transform: Bool.init) } /// Retrieves a `[JSON]` from a path into JSON or a fallback if not found. @@ -550,8 +549,8 @@ extension JSON { /// corresponding `JSON` value. /// * `TypeNotConvertible`: The target value's type inside of the `JSON` /// instance does not match the decoded value. - public func array(path: JSONPathType..., @autoclosure or fallback: () -> [JSON]) throws -> [JSON] { - return try mapOptionalAtPath(path, fallback: fallback, transform: JSON.getArray) + public func getArray(at path: JSONPathType..., or fallback: @autoclosure() -> [JSON]) throws -> [JSON] { + return try mapOptional(at: path, fallback: fallback, transform: JSON.getArray) } /// Attempts to decodes many values from a desendant JSON array at a path @@ -569,8 +568,8 @@ extension JSON { /// * `TypeNotConvertible`: The target value's type inside of the `JSON` /// instance does not match the decoded value. /// * Any error that arises from decoding the value. - public func arrayOf(path: JSONPathType..., @autoclosure or fallback: () -> [Decoded]) throws -> [Decoded] { - return try mapOptionalAtPath(path, fallback: fallback, transform: JSON.getArrayOf) + public func decodedArray(at path: JSONPathType..., or fallback: @autoclosure() -> [Decoded]) throws -> [Decoded] { + return try mapOptional(at: path, fallback: fallback, transform: JSON.decodedArray) } /// Retrieves a `[String: JSON]` from a path into JSON or a fallback if not @@ -587,8 +586,8 @@ extension JSON { /// corresponding `JSON` value. /// * `TypeNotConvertible`: The target value's type inside of the `JSON` /// instance does not match the decoded value. - public func dictionary(path: JSONPathType..., @autoclosure or fallback: () -> [Swift.String: JSON]) throws -> [Swift.String: JSON] { - return try mapOptionalAtPath(path, fallback: fallback, transform: JSON.getDictionary) + public func getDictionary(at path: JSONPathType..., or fallback: @autoclosure() -> [String: JSON]) throws -> [String: JSON] { + return try mapOptional(at: path, fallback: fallback, transform: JSON.getDictionary) } /// Attempts to decode many values from a descendant JSON object at a path @@ -606,111 +605,9 @@ extension JSON { /// * `TypeNotConvertible`: The target value's type inside of the `JSON` /// instance does not match the decoded value. /// * Any error that arises from decoding the value. - public func dictionaryOf(path: JSONPathType..., @autoclosure or fallback: () -> [Swift.String: Decoded]) throws -> [Swift.String: Decoded] { - return try mapOptionalAtPath(path, fallback: fallback, transform: JSON.getDictionaryOf) + public func decodedDictionary(at path: JSONPathType..., or fallback: @autoclosure() -> [String: Decoded]) throws -> [String: Decoded] { + return try mapOptional(at: path, fallback: fallback, transform: JSON.decodedDictionary) } } - -// MARK: - Deprecated methods - -extension JSON { - - @available(*, deprecated, message="Use 'decode(_:alongPath:type:)' with options '[.MissingKeyBecomesNil]'") - public func decode(path: JSONPathType..., ifNotFound: Swift.Bool, type: Decoded.Type = Decoded.self) throws -> Decoded? { - let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : [] - return try mapOptionalAtPath(path, alongPath: options, transform: Decoded.init) - } - - @available(*, deprecated, message="Use 'decode(_:alongPath:type:)' with options '[.NullBecomesNil]'") - public func decode(path: JSONPathType..., ifNull: Swift.Bool, type: Decoded.Type = Decoded.self) throws -> Decoded? { - let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : [] - return try mapOptionalAtPath(path, alongPath: options, transform: Decoded.init) - } - - @available(*, deprecated, message="Use 'double(_:alongPath:)' with options '[.MissingKeyBecomesNil]'") - public func double(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> Swift.Double? { - let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : [] - return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Double.init) - } - - @available(*, deprecated, message="Use 'double(_:alongPath:)' with options '[.NullBecomesNil]'") - public func double(path: JSONPathType..., ifNull: Swift.Bool) throws -> Swift.Double? { - let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : [] - return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Double.init) - } - - @available(*, deprecated, message="Use 'int(_:alongPath:)' with options '[.MissingKeyBecomesNil]'") - public func int(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> Swift.Int? { - let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : [] - return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Int.init) - } - - @available(*, deprecated, message="Use 'int(_:alongPath:)' with options '[.NullBecomesNil]'") - public func int(path: JSONPathType..., ifNull: Swift.Bool) throws -> Swift.Int? { - let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : [] - return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Int.init) - } - - @available(*, deprecated, message="Use 'string(_:alongPath:)' with options '[.MissingKeyBecomesNil]'") - public func string(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> Swift.String? { - let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : [] - return try mapOptionalAtPath(path, alongPath: options, transform: Swift.String.init) - } - - @available(*, deprecated, message="Use 'string(_:alongPath:)' with options '[.NullBecomesNil]'") - public func string(path: JSONPathType..., ifNull: Swift.Bool) throws -> Swift.String? { - let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : [] - return try mapOptionalAtPath(path, alongPath: options, transform: Swift.String.init) - } - - @available(*, deprecated, message="Use 'bool(_:alongPath:)' with options '[.MissingKeyBecomesNil]'") - public func bool(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> Swift.Bool? { - let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : [] - return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Bool.init) - } - - @available(*, deprecated, message="Use 'bool(_:alongPath:)' with options '[.NullBecomesNil]'") - public func bool(path: JSONPathType..., ifNull: Swift.Bool) throws -> Swift.Bool? { - let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : [] - return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Bool.init) - } - - @available(*, deprecated, message="Use 'array(_:alongPath:)' with options '[.MissingKeyBecomesNil]'") - public func array(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> [JSON]? { - let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : [] - return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArray) - } - - @available(*, deprecated, message="Use 'array(_:alongPath:)' with options '[.NullBecomesNil]'") - public func array(path: JSONPathType..., ifNull: Swift.Bool) throws -> [JSON]? { - let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : [] - return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArray) - } - - @available(*, deprecated, message="Use 'arrayOf(_:alongPath:)' with options '[.MissingKeyBecomesNil]'") - public func arrayOf(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> [Decoded]? { - let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : [] - return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArrayOf) - } - - @available(*, deprecated, message="Use 'arrayOf(_:alongPath:)' with options '[.NullBecomesNil]'") - public func arrayOf(path: JSONPathType..., ifNull: Swift.Bool) throws -> [Decoded]? { - let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : [] - return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArrayOf) - } - - @available(*, deprecated, message="Use 'dictionary(_:alongPath:)' with options '[.MissingKeyBecomesNil]'") - public func dictionary(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> [Swift.String: JSON]? { - let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : [] - return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getDictionary) - } - - @available(*, deprecated, message="Use 'dictionary(_:alongPath:)' with options '[.NullBecomesNil]'") - public func dictionary(path: JSONPathType..., ifNull: Swift.Bool) throws -> [Swift.String: JSON]? { - let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : [] - return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getDictionary) - } - -} diff --git a/Tests/JSONDecodableTests.swift b/Tests/JSONDecodableTests.swift index 06a2cffb..5db39913 100644 --- a/Tests/JSONDecodableTests.swift +++ b/Tests/JSONDecodableTests.swift @@ -52,7 +52,7 @@ class JSONDecodableTests: XCTestCase { do { _ = try Double(json: "bad") XCTFail("Should not be able to instantiate `Double` with `String` `JSON`.") - } catch JSON.Error.ValueNotConvertible(let type) { + } catch JSON.Error.valueNotConvertible(let type) { XCTAssert(true, "\(type) should not be covertible from 'bad' `String`.") } catch { XCTFail("Failed for unknown reason: \(error).") @@ -76,7 +76,7 @@ class JSONDecodableTests: XCTestCase { do { _ = try Int(json: "bad") XCTFail("Should not be able to instantiate `Int` with `String` `JSON`.") - } catch JSON.Error.ValueNotConvertible(let type) { + } catch JSON.Error.valueNotConvertible(let type) { XCTAssert(true, "\(type) should not be covertible from 'bad' `String`.") } catch { XCTFail("Failed for unknown reason: \(error).") @@ -97,7 +97,7 @@ class JSONDecodableTests: XCTestCase { do { let four = try String(json: 4) XCTAssertEqual(four, "4", "`four` and `4` should be equal.") - } catch JSON.Error.ValueNotConvertible(let type) { + } catch JSON.Error.valueNotConvertible(let type) { XCTAssert(true, "\(type) should be covertible from `Int.") } catch { XCTFail("Failed for unknown reason: \(error).") @@ -106,7 +106,7 @@ class JSONDecodableTests: XCTestCase { do { let twoAndHalf = try String(json: 2.5) XCTAssertEqual(twoAndHalf, "2.5", "`twoAndHalf` and `2.5` should be equal.") - } catch JSON.Error.ValueNotConvertible(let type) { + } catch JSON.Error.valueNotConvertible(let type) { XCTAssert(true, "\(type) should be covertible from `Double.") } catch { XCTFail("Failed for unknown reason: \(error).") @@ -115,7 +115,7 @@ class JSONDecodableTests: XCTestCase { do { let positive = try String(json: true) XCTAssertEqual(positive, "true", "`positive` and `true` should be equal.") - } catch JSON.Error.ValueNotConvertible(let type) { + } catch JSON.Error.valueNotConvertible(let type) { XCTAssert(true, "\(type) should be covertible from `Bool.") } catch { XCTFail("Failed for unknown reason: \(error).") @@ -136,7 +136,7 @@ class JSONDecodableTests: XCTestCase { do { _ = try Bool(json: "bad") XCTFail("Should not be able to instantiate `Bool` with `String` `JSON`.") - } catch JSON.Error.ValueNotConvertible(let type) { + } catch JSON.Error.valueNotConvertible(let type) { XCTAssert(true, "\(type) should not be covertible from 'bad' string.") } catch { XCTFail("Failed for unknown reason: \(error).") @@ -146,7 +146,7 @@ class JSONDecodableTests: XCTestCase { func testThatJSONBoolIsDecodable() { let JSONTrue: JSON = true do { - let decodedTrue = try JSONTrue.bool() + let decodedTrue = try JSONTrue.getBool() XCTAssertTrue(decodedTrue, "`JSONTrue` should decode to `true`.") } catch { XCTFail("`JSONTrue` should decode to `true`.") @@ -157,7 +157,7 @@ class JSONDecodableTests: XCTestCase { let JSONArray: JSON = [1,2,3,4] do { - let decodedArray = try JSONArray.array() + let decodedArray = try JSONArray.getArray() XCTAssertEqual(decodedArray, [1,2,3,4], "`decodedArray` should match.") } catch { XCTFail("`decodedArray should be [1,2,3,4]") @@ -165,9 +165,9 @@ class JSONDecodableTests: XCTestCase { let badJSONArray: JSON = "bad" do { - _ = try badJSONArray.array() + _ = try badJSONArray.getArray() XCTFail("array should not exist.") - } catch JSON.Error.ValueNotConvertible(let type) { + } catch JSON.Error.valueNotConvertible(let type) { XCTAssert(true, "\(type) should not be convertible to `[JSON]`") } catch { XCTFail("Failed for unknown reason: \(error).") @@ -178,7 +178,7 @@ class JSONDecodableTests: XCTestCase { let JSONDictionary: JSON = ["Matt": 32] do { - let decodedJSONDictionary = try JSONDictionary.dictionary() + let decodedJSONDictionary = try JSONDictionary.getDictionary() XCTAssertEqual(decodedJSONDictionary, ["Matt": 32], "`decodedJSONDictionary` should equal `[Matt: 32]`.") } catch { XCTFail("`decodedJSONDictionary` should equal `[Matt: 32]`.") @@ -186,9 +186,9 @@ class JSONDecodableTests: XCTestCase { let badJSONDictionary: JSON = 4 do { - _ = try badJSONDictionary.dictionary() + _ = try badJSONDictionary.getDictionary() XCTFail("There should be no dictionary.") - } catch JSON.Error.ValueNotConvertible(let type) { + } catch JSON.Error.valueNotConvertible(let type) { XCTAssertTrue(true, "\(type) shold not be convertible to `[String: JSON]`.") } catch { XCTFail("Failed for unknown reason: \(error).") @@ -199,7 +199,7 @@ class JSONDecodableTests: XCTestCase { let oneTwoThreeJSON: JSON = [1,2,3] do { - let decodedOneTwoThree = try oneTwoThreeJSON.arrayOf(type: Swift.Int) + let decodedOneTwoThree = try oneTwoThreeJSON.decodedArray(type: Swift.Int) XCTAssertEqual(decodedOneTwoThree, [1,2,3], "`decodedOneTwoThree` should be equal to `[1,2,3]`.") } catch { XCTFail("`decodedOneTwoThree` should be equal to `[1,2,3]`.") @@ -210,7 +210,7 @@ class JSONDecodableTests: XCTestCase { let oneTwoThreeJSON: JSON = ["one": 1, "two": 2, "three": 3] do { - let decodedOneTwoThree = try oneTwoThreeJSON.dictionaryOf(type: Swift.Int) + let decodedOneTwoThree = try oneTwoThreeJSON.decodedDictionary(type: Swift.Int) XCTAssertEqual(decodedOneTwoThree, ["one": 1, "two": 2, "three": 3], "`decodedOneTwoThree` should be equal to `[\"one\": 1, \"two\": 2, \"three\": 3]`.") } catch { XCTFail("`decodedOneTwoThree` should be equal to `[\"one\": 1, \"two\": 2, \"three\": 3]`.") @@ -218,10 +218,10 @@ class JSONDecodableTests: XCTestCase { } func testThatNullIsDecodedToNilWhenRequestedAtTopLevel() { - let JSONDictionary: JSON = ["key": .Null] + let JSONDictionary: JSON = ["key": .null] do { - let value: Int? = try JSONDictionary.int("key", alongPath: .NullBecomesNil) + let value: Int? = try JSONDictionary.getInt(at: "key", alongPath: .NullBecomesNil) XCTAssertEqual(value, nil) } catch { XCTFail("Should have retrieved nil for key `key` in `JSONDictionary` when specifying `ifNull` to be `true`.") @@ -229,12 +229,12 @@ class JSONDecodableTests: XCTestCase { } func testThatAttemptingToDecodeNullThrowsWhenRequestedAtTopLevel() { - let JSONDictionary: JSON = ["key": .Null] + let JSONDictionary: JSON = ["key": .null] do { - let _: Int? = try JSONDictionary.int("key") + let _: Int? = try JSONDictionary.getInt(at: "key") XCTFail("Should have thrown an error when attempting to retrieve a value for key `key` in `JSONDictionary` when not specifying `ifNull` to be `true`.") - } catch let JSON.Error.ValueNotConvertible(_, to) where to == Int.self { + } catch let JSON.Error.valueNotConvertible(_, to) where to == Int.self { return } catch { XCTFail("An unexpected exception was thrown.") @@ -250,4 +250,4 @@ public func ==(lhs: Person, rhs: Person) -> Bool { return (lhs.name == rhs.name) && (lhs.age == rhs.age) && (lhs.spouse == rhs.spouse) -} \ No newline at end of file +} diff --git a/Tests/JSONEncodableTests.swift b/Tests/JSONEncodableTests.swift index c284998b..5b2228a9 100644 --- a/Tests/JSONEncodableTests.swift +++ b/Tests/JSONEncodableTests.swift @@ -13,7 +13,7 @@ class JSONEncodableTests: XCTestCase { func testThatJSONEncodableEncodesString() { let matt = "Matt" - let comparisonMatt = JSON.String(matt) + let comparisonMatt = JSON.string(matt) let testMatt = matt.toJSON() XCTAssertTrue(comparisonMatt == testMatt, "These should be the same!") } @@ -27,14 +27,14 @@ class JSONEncodableTests: XCTestCase { func testThatJSONEncodableEncodesInt() { let thirtyTwo = 32 - let comparisonThirtyTwo = JSON.Int(thirtyTwo) + let comparisonThirtyTwo = JSON.int(thirtyTwo) let testThirtyTwo = thirtyTwo.toJSON() XCTAssertTrue(comparisonThirtyTwo == testThirtyTwo, "These should be the same!") } func testThatJSONEncodableEncodesDouble() { let threePointOneFour = 3.14 - let comparisonThreePointOneFour = JSON.Double(threePointOneFour) + let comparisonThreePointOneFour = JSON.double(threePointOneFour) let testThreePointOneFour = threePointOneFour.toJSON() XCTAssertTrue(comparisonThreePointOneFour == testThreePointOneFour, "These should be the same!") } @@ -48,7 +48,7 @@ class JSONEncodableTests: XCTestCase { func testThatJSONEncodableEncodesArray() { let veggies = ["lettuce", "onion"] - let comparisonVeggies = JSON.Array(["lettuce", "onion"]) + let comparisonVeggies = JSON.array(["lettuce", "onion"]) let testVeggies = veggies.toJSON() XCTAssertTrue(comparisonVeggies == testVeggies, "These should be the same!") } @@ -67,4 +67,4 @@ class JSONEncodableTests: XCTestCase { let testPeople = people.toJSON() XCTAssertTrue(comparisonPeople == testPeople, "These should be the same!") } -} \ No newline at end of file +} diff --git a/Tests/JSONEncodingDetectorTests.swift b/Tests/JSONEncodingDetectorTests.swift index e9b512cc..d41cc097 100644 --- a/Tests/JSONEncodingDetectorTests.swift +++ b/Tests/JSONEncodingDetectorTests.swift @@ -16,28 +16,28 @@ class JSONEncodingDetectorTests: XCTestCase { // MARK: - UTF16 func testUTF16LittleEndianDetection() { - let expectedEncoding: JSONEncodingDetector.Encoding = .UTF16LE + let expectedEncoding: JSONEncodingDetector.Encoding = .utf16LE let encoding = fixtures.withPrefixSlice(expectedEncoding, includeBOM: false, body: JSONEncodingDetector.detectEncoding).encoding XCTAssertEqual(encoding, expectedEncoding) } func testUTF16LittleEndianWithBOMDetection() { - let expectedEncoding: JSONEncodingDetector.Encoding = .UTF16LE - let encodingPrefixInformation = fixtures.withPrefixSlice(.UTF16LE, includeBOM: true, body: JSONEncodingDetector.detectEncoding) + let expectedEncoding: JSONEncodingDetector.Encoding = .utf16LE + let encodingPrefixInformation = fixtures.withPrefixSlice(.utf16LE, includeBOM: true, body: JSONEncodingDetector.detectEncoding) // TODO: Swift 2.2 replace with a single XCTAssertEqual for the `ByteStreamPrefixInformation` tuple XCTAssertEqual(encodingPrefixInformation.encoding, expectedEncoding) XCTAssertEqual(encodingPrefixInformation.byteOrderMarkLength, 2) } func testUTF16BigEndianDetection() { - let expectedEncoding: JSONEncodingDetector.Encoding = .UTF16BE - let encoding = fixtures.withPrefixSlice(.UTF16BE, includeBOM: false, body: JSONEncodingDetector.detectEncoding).encoding + let expectedEncoding: JSONEncodingDetector.Encoding = .utf16BE + let encoding = fixtures.withPrefixSlice(.utf16BE, includeBOM: false, body: JSONEncodingDetector.detectEncoding).encoding XCTAssertEqual(encoding, expectedEncoding) } func testUTF16BigEndianWithBOMDetection() { - let expectedEncoding: JSONEncodingDetector.Encoding = .UTF16BE - let encodingPrefixInformation = fixtures.withPrefixSlice(.UTF16BE, includeBOM: true, body: JSONEncodingDetector.detectEncoding) + let expectedEncoding: JSONEncodingDetector.Encoding = .utf16BE + let encodingPrefixInformation = fixtures.withPrefixSlice(.utf16BE, includeBOM: true, body: JSONEncodingDetector.detectEncoding) // TODO: Swift 2.2 replace with a single XCTAssertEqual for the `ByteStreamPrefixInformation` tuple XCTAssertEqual(encodingPrefixInformation.encoding, expectedEncoding) XCTAssertEqual(encodingPrefixInformation.byteOrderMarkLength, 2) @@ -46,28 +46,28 @@ class JSONEncodingDetectorTests: XCTestCase { // MARK: - UTF32 func testUTF32LittleEndianDetection() { - let expectedEncoding: JSONEncodingDetector.Encoding = .UTF32LE + let expectedEncoding: JSONEncodingDetector.Encoding = .utf32LE let encoding = fixtures.withPrefixSlice(expectedEncoding, includeBOM: false, body: JSONEncodingDetector.detectEncoding).encoding XCTAssertEqual(encoding, expectedEncoding) } func testUTF32LittleEndianWithBOMDetection() { - let expectedEncoding: JSONEncodingDetector.Encoding = .UTF32LE - let encodingPrefixInformation = fixtures.withPrefixSlice(.UTF32LE, includeBOM: true, body: JSONEncodingDetector.detectEncoding) + let expectedEncoding: JSONEncodingDetector.Encoding = .utf32LE + let encodingPrefixInformation = fixtures.withPrefixSlice(.utf32LE, includeBOM: true, body: JSONEncodingDetector.detectEncoding) // TODO: Swift 2.2 replace with a single XCTAssertEqual for the `ByteStreamPrefixInformation` tuple XCTAssertEqual(encodingPrefixInformation.encoding, expectedEncoding) XCTAssertEqual(encodingPrefixInformation.byteOrderMarkLength, 4) } func testUTF32BigEndianDetection() { - let expectedEncoding: JSONEncodingDetector.Encoding = .UTF32BE - let encoding = fixtures.withPrefixSlice(.UTF32BE, includeBOM: false, body: JSONEncodingDetector.detectEncoding).encoding + let expectedEncoding: JSONEncodingDetector.Encoding = .utf32BE + let encoding = fixtures.withPrefixSlice(.utf32BE, includeBOM: false, body: JSONEncodingDetector.detectEncoding).encoding XCTAssertEqual(encoding, expectedEncoding) } func testUTF32BigEndianWithBOMDetection() { - let expectedEncoding: JSONEncodingDetector.Encoding = .UTF32BE - let encodingPrefixInformation = fixtures.withPrefixSlice(.UTF32BE, includeBOM: true, body: JSONEncodingDetector.detectEncoding) + let expectedEncoding: JSONEncodingDetector.Encoding = .utf32BE + let encodingPrefixInformation = fixtures.withPrefixSlice(.utf32BE, includeBOM: true, body: JSONEncodingDetector.detectEncoding) // TODO: Swift 2.2 replace with a single XCTAssertEqual for the `ByteStreamPrefixInformation` tuple XCTAssertEqual(encodingPrefixInformation.encoding, expectedEncoding) XCTAssertEqual(encodingPrefixInformation.byteOrderMarkLength,4) @@ -76,14 +76,14 @@ class JSONEncodingDetectorTests: XCTestCase { // MARK: - UTF8 func testUTF8Detection() { - let expectedEncoding: JSONEncodingDetector.Encoding = .UTF8 - let encoding = fixtures.withPrefixSlice(.UTF8, includeBOM: false, body: JSONEncodingDetector.detectEncoding).encoding + let expectedEncoding: JSONEncodingDetector.Encoding = .utf8 + let encoding = fixtures.withPrefixSlice(.utf8, includeBOM: false, body: JSONEncodingDetector.detectEncoding).encoding XCTAssertEqual(encoding, expectedEncoding) } func testUTF8WithBOMDetection() { - let expectedEncoding: JSONEncodingDetector.Encoding = .UTF8 - let encodingPrefixInformation = fixtures.withPrefixSlice(.UTF8, includeBOM: true, body: JSONEncodingDetector.detectEncoding) + let expectedEncoding: JSONEncodingDetector.Encoding = .utf8 + let encodingPrefixInformation = fixtures.withPrefixSlice(.utf8, includeBOM: true, body: JSONEncodingDetector.detectEncoding) // TODO: Swift 2.2 replace with a single XCTAssertEqual for the `ByteStreamPrefixInformation` tuple XCTAssertEqual(encodingPrefixInformation.encoding, expectedEncoding) XCTAssertEqual(encodingPrefixInformation.byteOrderMarkLength, 3) @@ -92,25 +92,25 @@ class JSONEncodingDetectorTests: XCTestCase { struct JSONEncodingUTFTestFixtures { - func hexArray(encoding: JSONEncodingDetector.Encoding, includeBOM: Bool) -> [UInt8] { + func hexArray(_ encoding: JSONEncodingDetector.Encoding, includeBOM: Bool) -> [UInt8] { switch encoding { - case .UTF8: + case .utf8: return includeBOM ? utf8BOM + utf8Hex : utf8Hex - case .UTF16LE: + case .utf16LE: return includeBOM ? utf16LEBOM + utf16LEHex : utf16LEHex - case .UTF16BE: + case .utf16BE: return includeBOM ? utf16BEBOM + utf16BEHex : utf16BEHex - case .UTF32LE: + case .utf32LE: return includeBOM ? utf32LEBOM + utf32LEHex : utf32LEHex - case .UTF32BE: + case .utf32BE: return includeBOM ? utf32BEBOM + utf32BEHex : utf32BEHex } } - func withPrefixSlice(encoding: JSONEncodingDetector.Encoding, includeBOM: Bool, @noescape body: Slice> -> R) -> R { + func withPrefixSlice(_ encoding: JSONEncodingDetector.Encoding, includeBOM: Bool, body: (RandomAccessSlice>) throws -> R) rethrows -> R { let array = hexArray(encoding, includeBOM: includeBOM) - return array.withUnsafeBufferPointer() { - body($0.prefix(4)) + return try array.withUnsafeBufferPointer { + try body($0.prefix(4)) } } diff --git a/Tests/JSONParserTests.swift b/Tests/JSONParserTests.swift index 3fb3eafa..4d72c000 100644 --- a/Tests/JSONParserTests.swift +++ b/Tests/JSONParserTests.swift @@ -11,31 +11,31 @@ import Freddy private func ==(lhs: JSONParser.Error, rhs: JSONParser.Error) -> Bool { switch (lhs, rhs) { - case (.EndOfStreamUnexpected, .EndOfStreamUnexpected): + case (.endOfStreamUnexpected, .endOfStreamUnexpected): return true - case let (.EndOfStreamGarbage(lOffset), .EndOfStreamGarbage(rOffset)): + case let (.endOfStreamGarbage(lOffset), .endOfStreamGarbage(rOffset)): return lOffset == rOffset - case let (.ExceededNestingLimit(lOffset), .ExceededNestingLimit(rOffset)): + case let (.exceededNestingLimit(lOffset), .exceededNestingLimit(rOffset)): return lOffset == rOffset - case let (.ValueInvalid(lOffset, lValue), .ValueInvalid(rOffset, rValue)): + case let (.valueInvalid(lOffset, lValue), .valueInvalid(rOffset, rValue)): return lOffset == rOffset && lValue == rValue - case let (.ControlCharacterUnrecognized(lOffset), .ControlCharacterUnrecognized(rOffset)): + case let (.controlCharacterUnrecognized(lOffset), .controlCharacterUnrecognized(rOffset)): return lOffset == rOffset - case let (.UnicodeEscapeInvalid(lOffset), .UnicodeEscapeInvalid(rOffset)): + case let (.unicodeEscapeInvalid(lOffset), .unicodeEscapeInvalid(rOffset)): return lOffset == rOffset - case let (.LiteralNilMisspelled(lOffset), .LiteralNilMisspelled(rOffset)): + case let (.literalNilMisspelled(lOffset), .literalNilMisspelled(rOffset)): return lOffset == rOffset - case let (.LiteralTrueMisspelled(lOffset), .LiteralTrueMisspelled(rOffset)): + case let (.literalTrueMisspelled(lOffset), .literalTrueMisspelled(rOffset)): return lOffset == rOffset - case let (.LiteralFalseMisspelled(lOffset), .LiteralFalseMisspelled(rOffset)): + case let (.literalFalseMisspelled(lOffset), .literalFalseMisspelled(rOffset)): return lOffset == rOffset - case let (.CollectionMissingSeparator(lOffset), .CollectionMissingSeparator(rOffset)): + case let (.collectionMissingSeparator(lOffset), .collectionMissingSeparator(rOffset)): return lOffset == rOffset - case let (.DictionaryMissingKey(lOffset), .DictionaryMissingKey(rOffset)): + case let (.dictionaryMissingKey(lOffset), .dictionaryMissingKey(rOffset)): return lOffset == rOffset - case let (.NumberMissingFractionalDigits(lOffset), .NumberMissingFractionalDigits(rOffset)): + case let (.numberMissingFractionalDigits(lOffset), .numberMissingFractionalDigits(rOffset)): return lOffset == rOffset - case let (.NumberSymbolMissingDigits(lOffset), .NumberSymbolMissingDigits(rOffset)): + case let (.numberSymbolMissingDigits(lOffset), .numberSymbolMissingDigits(rOffset)): return lOffset == rOffset case (_, _): return false @@ -44,31 +44,26 @@ private func ==(lhs: JSONParser.Error, rhs: JSONParser.Error) -> Bool { class JSONParserTests: XCTestCase { - private func JSONFromString(s: String) throws -> JSON { - var parser = JSONParser(string: s) - return try parser.parse() - } - - func testThatParserThrowsAnErrorForAnEmptyNSData() { + func testThatParserThrowsAnErrorForAnEmptyData() { do { - _ = try JSONFromString("") + _ = try JSONParser.parse("") XCTFail("Unexpectedly did not throw an error") } catch let error as JSONParser.Error { - XCTAssert(error == JSONParser.Error.EndOfStreamUnexpected) + XCTAssert(error == JSONParser.Error.endOfStreamUnexpected) } catch { XCTFail("Unexpected error \(error)") } } - func testThatParserThrowsErrorForInsufficientNSData() { + func testThatParserThrowsErrorForInsufficientData() { let hex: [UInt8] = [0x7B] - let data = NSData(bytes: hex, length: hex.count) + let data = Data(bytes: UnsafePointer(hex), count: hex.count) do { - try JSONParser.createJSONFromData(data) + _ = try JSONParser.parse(utf8: data) XCTFail("Unexpectedly did not throw an error") - } catch JSONParser.Error.EndOfStreamUnexpected { + } catch JSONParser.Error.endOfStreamUnexpected { return } catch { XCTFail("Incorrect error received.: \(error)") @@ -76,13 +71,13 @@ class JSONParserTests: XCTestCase { } func testThatParserCompletesWithSingleZero() { - guard let data = "0".dataUsingEncoding(NSUTF8StringEncoding) else { + guard let data = "0".data(using: String.Encoding.utf8) else { XCTFail("Cannot create data from string") return } do { - try JSONParser.createJSONFromData(data) + _ = try JSONParser.parse(utf8: data) } catch { XCTFail("Unexpected error \(error)") } @@ -90,34 +85,34 @@ class JSONParserTests: XCTestCase { func testThatParserCompletesWithBOMAndSingleZero() { let hex: [UInt8] = [0xEF, 0xBB, 0xBF, 0x30] - let data = NSData(bytes: hex, length: hex.count) + let data = Data(bytes: UnsafePointer(hex), count: hex.count) do { - try JSONParser.createJSONFromData(data) + _ = try JSONParser.parse(utf8: data) } catch { XCTFail("Unexpected error \(error)") } } func testThatParserUnderstandsNull() { - let value = try! JSONFromString("null") - XCTAssertEqual(value, JSON.Null) + let value = try! JSONParser.parse("null") + XCTAssertEqual(value, JSON.null) } func testThatParserSkipsLeadingWhitespace() { - let value = try! JSONFromString(" \t\r\nnull") - XCTAssertEqual(value, JSON.Null) + let value = try! JSONParser.parse(" \t\r\nnull") + XCTAssertEqual(value, JSON.null) } func testThatParserAllowsTrailingWhitespace() { - let value = try! JSONFromString("null ") - XCTAssertEqual(value, JSON.Null) + let value = try! JSONParser.parse("null ") + XCTAssertEqual(value, JSON.null) } func testThatParserFailsWhenTrailingDataIsPresent() { do { - _ = try JSONFromString("null true") - } catch JSONParser.Error.EndOfStreamGarbage(let offset) { + _ = try JSONParser.parse("null true") + } catch JSONParser.Error.endOfStreamGarbage(let offset) { XCTAssertEqual(offset, 7) } catch { XCTFail("Unexpected error \(error)") @@ -125,40 +120,40 @@ class JSONParserTests: XCTestCase { } func testThatParserUnderstandsTrue() { - let value = try! JSONFromString("true") - XCTAssertEqual(value, JSON.Bool(true)) + let value = try! JSONParser.parse("true") + XCTAssertEqual(value, JSON.bool(true)) } func testThatParserUnderstandsFalse() { - let value = try! JSONFromString("false") - XCTAssertEqual(value, JSON.Bool(false)) + let value = try! JSONParser.parse("false") + XCTAssertEqual(value, JSON.bool(false)) } func testThatParserUnderstandsStringsWithoutEscapes() { let string = "a b c d 😀 x y z" - let value = try! JSONFromString("\"\(string)\"") - XCTAssertEqual(value, JSON.String(string)) + let value = try! JSONParser.parse("\"\(string)\"") + XCTAssertEqual(value, JSON.string(string)) } func testThatParserUnderstandsStringsWithEscapedCharacters() { let expect = " \" \\ / \n \r \t \u{000c} \u{0008} " - let value = try! JSONFromString("\" \\\" \\\\ \\/ \\n \\r \\t \\f \\b \"") - XCTAssertEqual(value, JSON.String(expect)) + let value = try! JSONParser.parse("\" \\\" \\\\ \\/ \\n \\r \\t \\f \\b \"") + XCTAssertEqual(value, JSON.string(expect)) } func testThatParserUnderstandsStringsWithEscapedUnicode() { // try 1-, 2-, and 3-byte UTF8 sequences let expect = "\u{0060}\u{012a}\u{12AB}" - let value = try! JSONFromString("\"\\u0060\\u012a\\u12AB\"") - XCTAssertEqual(value, JSON.String(expect)) + let value = try! JSONParser.parse("\"\\u0060\\u012a\\u12AB\"") + XCTAssertEqual(value, JSON.string(expect)) } func testThatParserFailsWhenIncompleteDataIsPresent() { for s in [" ", "[0,", "{\"\":"] { do { - let value = try JSONFromString(" ") + let value = try JSONParser.parse(" ") XCTFail("Unexpectedly parsed \(s) as \(value)") - } catch JSONParser.Error.EndOfStreamUnexpected { + } catch JSONParser.Error.endOfStreamUnexpected { // expected error - do nothing } catch { XCTFail("Unexpected error \(error)") @@ -182,7 +177,7 @@ class JSONParserTests: XCTestCase { ("0.1e0001", 1), ] { do { - let value = try JSONFromString(string).int() + let value = try JSONParser.parse(string).getInt() XCTAssertEqual(value, shouldBeInt) } catch { XCTFail("Unexpected error: \(error)") @@ -203,7 +198,7 @@ class JSONParserTests: XCTestCase { ("-0.1E-1", -0.01), ] { do { - let value = try JSONFromString(string).double() + let value = try JSONParser.parse(string).getDouble() XCTAssertEqualWithAccuracy(value, shouldBeDouble, accuracy: DBL_EPSILON) } catch { XCTFail("Unexpected error: \(error)") @@ -213,17 +208,17 @@ class JSONParserTests: XCTestCase { func testThatParserRejectsInvalidNumbers() { for (string, expectedError) in [ - ("012", JSONParser.Error.EndOfStreamGarbage(offset: 1)), - ("0.1.2", JSONParser.Error.EndOfStreamGarbage(offset: 3)), - ("-.123", JSONParser.Error.NumberSymbolMissingDigits(offset: 0)), - (".123", JSONParser.Error.ValueInvalid(offset: 0, character: ".")), - ("1.", JSONParser.Error.EndOfStreamUnexpected), - ("1.0e", JSONParser.Error.EndOfStreamUnexpected), - ("1.0e+", JSONParser.Error.EndOfStreamUnexpected), - ("1.0e-", JSONParser.Error.EndOfStreamUnexpected), + ("012", JSONParser.Error.endOfStreamGarbage(offset: 1)), + ("0.1.2", JSONParser.Error.endOfStreamGarbage(offset: 3)), + ("-.123", JSONParser.Error.numberSymbolMissingDigits(offset: 0)), + (".123", JSONParser.Error.valueInvalid(offset: 0, character: ".")), + ("1.", JSONParser.Error.endOfStreamUnexpected), + ("1.0e", JSONParser.Error.endOfStreamUnexpected), + ("1.0e+", JSONParser.Error.endOfStreamUnexpected), + ("1.0e-", JSONParser.Error.endOfStreamUnexpected), ] { do { - let value = try JSONFromString(string) + let value = try JSONParser.parse(string) XCTFail("Unexpectedly parsed \(string) as \(value)") } catch let error as JSONParser.Error { XCTAssert(error == expectedError) @@ -245,10 +240,10 @@ class JSONParserTests: XCTestCase { "4.9406564584124654E-325", ] { do { - let json = try JSONFromString(string) + let json = try JSONParser.parse(string) // numbers overflow, but we should be able to get them out as strings - XCTAssertEqual(try? json.string(), string) + XCTAssertEqual(try? json.getString(), string) } catch { XCTFail("Unexpected error \(error)") } @@ -265,14 +260,14 @@ class JSONParserTests: XCTestCase { let anyValueExceedingIntMax = UInt.max let jsonString = "{\"exceedsIntMax\": \(anyValueExceedingIntMax)}" - let data = jsonString.dataUsingEncoding(NSUTF8StringEncoding)! - guard let json = try? JSON(data: data, usingParser: NSJSONSerialization.self) else { + let data = jsonString.data(using: String.Encoding.utf8)! + guard let json = try? JSON(data: data, usingParser: JSONSerialization.self) else { XCTFail("Failed to even parse JSON: \(jsonString)") return } - XCTAssertEqual(try? json.int("exceedsIntMax"), nil, "as int") - XCTAssertEqual(try? json.double("exceedsIntMax"), Double(anyValueExceedingIntMax), "as double") + XCTAssertEqual(try? json.getInt(at: "exceedsIntMax"), nil, "as int") + XCTAssertEqual(try? json.getDouble(at: "exceedsIntMax"), Double(anyValueExceedingIntMax), "as double") } // This test should also be run on the iPhone 5 simulator to check 32-bit support. @@ -280,16 +275,16 @@ class JSONParserTests: XCTestCase { let anyValueExceedingIntMax = UInt.max let jsonString = "{\"exceedsIntMax\": \(anyValueExceedingIntMax)}" - let data = jsonString.dataUsingEncoding(NSUTF8StringEncoding)! + let data = jsonString.data(using: String.Encoding.utf8)! guard let json = try? JSON(data: data) else { XCTFail("Failed to even parse JSON: \(jsonString)") return } // The Freddy parser behaves consistently across architectures. - XCTAssertEqual(try? json.int("exceedsIntMax"), nil, "as int") - XCTAssertEqual(try? json.double("exceedsIntMax"), nil, "as double") - XCTAssertEqual(try? json.string("exceedsIntMax"), anyValueExceedingIntMax.description, "as string") + XCTAssertEqual(try? json.getInt(at: "exceedsIntMax"), nil, "as int") + XCTAssertEqual(try? json.getDouble(at: "exceedsIntMax"), nil, "as double") + XCTAssertEqual(try? json.getString(at: "exceedsIntMax"), anyValueExceedingIntMax.description, "as string") } // This was tripping a fatalError with the Freddy parser for 64-bit at one point: @@ -299,100 +294,100 @@ class JSONParserTests: XCTestCase { let anyFloatingPointValueExceedingIntMax = Double(UInt(Int.max) + 1) let jsonString = "{\"exceedsIntMax\": \(anyFloatingPointValueExceedingIntMax)}" - let data = jsonString.dataUsingEncoding(NSUTF8StringEncoding)! + let data = jsonString.data(using: String.Encoding.utf8)! guard let json = try? JSON(data: data) else { XCTFail("Failed to even parse JSON: \(jsonString)") return } - XCTAssertEqual(try? json.int("exceedsIntMax"), nil, "as int") + XCTAssertEqual(try? json.getInt(at: "exceedsIntMax"), nil, "as int") } func testThatParserUnderstandsEmptyArrays() { - let expect = JSON.Array([]) + let expect = JSON.array([]) for string in ["[]", "[ ]", " [ ] "] { - let value = try! JSONFromString(string) + let value = try! JSONParser.parse(string) XCTAssertEqual(value, expect) } } func testThatParserUnderstandsSingleItemArrays() { for (s, expect) in [ - (" [ null ] ", [JSON.Null]), - ("[true]", [JSON.Bool(true)]), - ("[ [\"nested\"]]", [JSON.Array([.String("nested")])]) + (" [ null ] ", [JSON.null]), + ("[true]", [JSON.bool(true)]), + ("[ [\"nested\"]]", [JSON.array([.string("nested")])]) ] { - let value = try! JSONFromString(s) - XCTAssertEqual(value, JSON.Array(expect)) + let value = try! JSONParser.parse(s) + XCTAssertEqual(value, JSON.array(expect)) } } func testThatParserUnderstandsMultipleItemArrays() { for (string, expect) in [ - (" [ null , \"foo\" ] ", [JSON.Null, .String("foo")]), - ("[true,true,false]", [JSON.Bool(true), .Bool(true), .Bool(false)]), + (" [ null , \"foo\" ] ", [JSON.null, .string("foo")]), + ("[true,true,false]", [JSON.bool(true), .bool(true), .bool(false)]), ("[ [\"nested\",null], [[\"doubly\",true]] ]", - [JSON.Array([.String("nested"), .Null]), - .Array([.Array([.String("doubly"), .Bool(true)])])]) + [JSON.array([.string("nested"), .null]), + .array([.array([.string("doubly"), .bool(true)])])]) ] { - let value = try! JSONFromString(string) - XCTAssertEqual(value, JSON.Array(expect)) + let value = try! JSONParser.parse(string) + XCTAssertEqual(value, JSON.array(expect)) } } func testThatParserUnderstandsEmptyObjects() { for string in ["{}", " { } "] { - let value = try! JSONFromString(string) - XCTAssertEqual(value, JSON.Dictionary([:])) + let value = try! JSONParser.parse(string) + XCTAssertEqual(value, JSON.dictionary([:])) } } func testThatParserUnderstandsSingleItemObjects() { for (string, expect) in [ - ("{\"a\":\"b\"}", ["a":JSON.String("b")]), - ("{ \"foo\" : [null] }", ["foo": JSON.Array([.Null])]), - ("{ \"a\" : { \"b\": true } }", ["a": JSON.Dictionary(["b":.Bool(true)])]), + ("{\"a\":\"b\"}", ["a":JSON.string("b")]), + ("{ \"foo\" : [null] }", ["foo": JSON.array([.null])]), + ("{ \"a\" : { \"b\": true } }", ["a": JSON.dictionary(["b":.bool(true)])]), ] { - let value = try! JSONFromString(string) - XCTAssertEqual(value, JSON.Dictionary(expect)) + let value = try! JSONParser.parse(string) + XCTAssertEqual(value, JSON.dictionary(expect)) } } func testThatParserUnderstandsMultipleItemObjects() { for (string, expect) in [ ("{\"a\":\"b\",\"c\":\"d\"}", - ["a":JSON.String("b"),"c":.String("d")]), + ["a":JSON.string("b"),"c":.string("d")]), ("{ \"foo\" : [null] , \"bar\": true }", - ["foo": JSON.Array([.Null]), "bar": .Bool(true)]), + ["foo": JSON.array([.null]), "bar": .bool(true)]), ("{ \"a\" : { \"b\": true }, \"c\": { \"x\" : true, \"y\": null } }", - ["a": JSON.Dictionary(["b":.Bool(true)]), - "c": .Dictionary(["x": .Bool(true), "y": .Null])]), + ["a": JSON.dictionary(["b":.bool(true)]), + "c": .dictionary(["x": .bool(true), "y": .null])]), ] { - let value = try! JSONFromString(string) - XCTAssertEqual(value, JSON.Dictionary(expect)) + let value = try! JSONParser.parse(string) + XCTAssertEqual(value, JSON.dictionary(expect)) } } func testThatParserFailsForUnsupportedEncodings() { let unsupportedEncodings: [JSONEncodingDetector.Encoding] = [ - .UTF16LE, - .UTF16BE, - .UTF32LE, - .UTF32BE + .utf16LE, + .utf16BE, + .utf32LE, + .utf32BE ] let fixtures = JSONEncodingUTFTestFixtures() for encoding in unsupportedEncodings { let hex = fixtures.hexArray(encoding, includeBOM: false) - let data = NSData(bytes: hex, length: hex.count) + let data = Data(bytes: UnsafePointer(hex), count: hex.count) let hexWithBOM = fixtures.hexArray(encoding, includeBOM: true) - let dataWithBOM = NSData(bytes: hexWithBOM, length: hexWithBOM.count) + let dataWithBOM = Data(bytes: UnsafePointer(hexWithBOM), count: hexWithBOM.count) do { - try JSONParser.createJSONFromData(data) - try JSONParser.createJSONFromData(dataWithBOM) + _ = try JSONParser.parse(utf8: data) + _ = try JSONParser.parse(utf8: dataWithBOM) XCTFail("Unexpectedly did not throw an error") - } catch JSONParser.Error.InvalidUnicodeStreamEncoding(_) { + } catch JSONParser.Error.invalidUnicodeStreamEncoding(_) { break } catch { XCTFail("Incorrect error received.: \(error)") @@ -406,7 +401,7 @@ class JSONParserTests: XCTestCase { ("\"\\ud83d\\ude39\\ud83d\\udc8d\"", "😹💍"), ] { do { - let json = try JSONFromString(jsonString) + let json = try JSONParser.parse(jsonString) let decoded: String = try json.decode() XCTAssertEqual(decoded, expected) } catch { @@ -422,9 +417,9 @@ class JSONParserTests: XCTestCase { "\"\\ud800abc\"", ] { do { - let _ = try JSONFromString(invalidPairString) + let _ = try JSONParser.parse(invalidPairString) XCTFail("Unexpectedly parsed invalid surrogate pair") - } catch JSONParser.Error.UnicodeEscapeInvalid { + } catch JSONParser.Error.unicodeEscapeInvalid { // do nothing - this is the expected error } catch { XCTFail("Unexpected error: \(error)") diff --git a/Tests/JSONSerializingTests.swift b/Tests/JSONSerializingTests.swift index 8928a388..3ddf0ed9 100644 --- a/Tests/JSONSerializingTests.swift +++ b/Tests/JSONSerializingTests.swift @@ -9,7 +9,7 @@ class JSONSerializingTests: XCTestCase { func testThatJSONCanBeSerializedToNSData() { let data = try! json.serialize() - XCTAssertGreaterThan(data.length, 0, "There should be data.") + XCTAssertGreaterThan(data.count, 0, "There should be data.") } func testThatJSONCanBeSerializedToString() { @@ -43,46 +43,46 @@ class JSONSerializingTests: XCTestCase { XCTAssert(json == serialJSON, "The JSON values should be equal.") } - func testThatJSONDataSerializationHandlesBoolsCorrectly() { - let json = JSON.Dictionary([ - "foo": .Bool(true), - "bar": .Bool(false), - "baz": .Int(123), + func testThatJSONSerializationHandlesBoolsCorrectly() { + let json = JSON.dictionary([ + "foo": .bool(true), + "bar": .bool(false), + "baz": .int(123), ]) let data = try! json.serialize() - let deserializedResult = try! JSON(data: data).dictionary() - let deserialized = JSON.Dictionary(deserializedResult) + let deserializedResult = try! JSON(data: data).getDictionary() + let deserialized = JSON.dictionary(deserializedResult) XCTAssertEqual(json, deserialized, "Serialize/Deserialize succeed with Bools") } func testThatJSONStringSerializationHandlesBoolsCorrectly() { - let json = JSON.Dictionary([ - "foo": .Bool(true), - "bar": .Bool(false), - "baz": .Int(123), + let json = JSON.dictionary([ + "foo": .bool(true), + "bar": .bool(false), + "baz": .int(123), ]) let string = try! json.serializeString() - let deserializedResult = try! JSON(jsonString: string).dictionary() - let deserialized = JSON.Dictionary(deserializedResult) + let deserializedResult = try! JSON(jsonString: string).getDictionary() + let deserialized = JSON.dictionary(deserializedResult) XCTAssertEqual(json, deserialized, "Serialize/Deserialize succeed with Bools") } } -func dataFromFixture(filename: String) -> NSData { - let testBundle = NSBundle(forClass: JSONSerializingTests.self) - guard let URL = testBundle.URLForResource(filename, withExtension: nil) else { +func dataFromFixture(_ filename: String) -> Data { + let testBundle = Bundle(for: JSONSerializingTests.self) + guard let URL = testBundle.url(forResource: filename, withExtension: nil) else { preconditionFailure("failed to find file \"\(filename)\" in bundle \(testBundle)") } - guard let data = NSData(contentsOfURL: URL) else { - preconditionFailure("NSData failed to read file \(URL.path)") + guard let data = try? Data(contentsOf: URL) else { + preconditionFailure("Data failed to read file \(URL.path)") } return data } -func JSONFromFixture(filename: String) -> JSON { +func JSONFromFixture(_ filename: String) -> JSON { let data = dataFromFixture(filename) do { let json = try JSON(data: data) diff --git a/Tests/JSONSubscriptingTests.swift b/Tests/JSONSubscriptingTests.swift index 734e94f1..a74d8af1 100644 --- a/Tests/JSONSubscriptingTests.swift +++ b/Tests/JSONSubscriptingTests.swift @@ -13,7 +13,7 @@ class JSONSubscriptingTests: XCTestCase { private var residentJSON: JSON! private var json: JSON! - private var noWhiteSpaceData: NSData! + private var noWhiteSpaceData: Data! func parser() -> JSONParserType.Type { return JSONParser.self @@ -22,43 +22,43 @@ class JSONSubscriptingTests: XCTestCase { override func setUp() { super.setUp() - residentJSON = JSON.Dictionary([ + residentJSON = .dictionary([ "residents": [ - ["name": "Matt", "age": 33, "hasPet": false, "rent": .Null], + ["name": "Matt", "age": 33, "hasPet": false, "rent": .null], ["name": "Drew", "hasPet": true, "rent": 1234.5], - ["name": "Pat", "age": 28, "hasPet": .Null] + ["name": "Pat", "age": 28, "hasPet": .null] ], "residentsByName": [ - "Matt": ["name": "Matt", "age": 33, "hasPet": false, "rent": .Null], + "Matt": ["name": "Matt", "age": 33, "hasPet": false, "rent": .null], "Drew": ["name": "Drew", "hasPet": true, "rent": 1234.5], - "Pat": ["name": "Pat", "age": 28, "hasPet": .Null] + "Pat": ["name": "Pat", "age": 28, "hasPet": .null] ] ]) - let testBundle = NSBundle(forClass: JSONSubscriptingTests.self) - guard let data = testBundle.URLForResource("sample", withExtension: "JSON").flatMap(NSData.init) else { + let testBundle = Bundle(for: JSONSubscriptingTests.self) + guard let data = testBundle.url(forResource: "sample", withExtension: "JSON").flatMap(NSData.init(contentsOf:)) else { XCTFail("Could not read sample data from test bundle") return } do { - self.json = try JSON(data: data, usingParser: parser()) + self.json = try JSON(data: data as Data, usingParser: parser()) } catch { XCTFail("Could not parse sample JSON: \(error)") return } - guard let noWhiteSpaceData = testBundle.URLForResource("sampleNoWhiteSpace", withExtension: "JSON").flatMap(NSData.init) else { + guard let noWhiteSpaceData = testBundle.url(forResource: "sampleNoWhiteSpace", withExtension: "JSON").flatMap(NSData.init(contentsOf:)) else { XCTFail("Could not read sample data (no whitespace) from test bundle") return } - self.noWhiteSpaceData = noWhiteSpaceData + self.noWhiteSpaceData = noWhiteSpaceData as Data } func testThatArrayOfProducesResidents() { do { - let residents = try residentJSON.arrayOf("residents", type: Resident.self) + let residents = try residentJSON.decodedArray(at: "residents", type: Resident.self) let residentsNames = residents.map { $0.name } XCTAssertEqual(residentsNames.count, 3, "There should be 3 residents.") } catch { @@ -68,7 +68,7 @@ class JSONSubscriptingTests: XCTestCase { func testThatDictionaryOfProducesResidentsByName() { do { - let residentsByName = try residentJSON.dictionaryOf("residentsByName", type: Resident.self) + let residentsByName = try residentJSON.decodedDictionary(at: "residentsByName", type: Resident.self) let residentsNames = residentsByName.map { $1.name } XCTAssertEqual(residentsNames.count, 3, "There should be 3 residents.") } catch { @@ -78,7 +78,7 @@ class JSONSubscriptingTests: XCTestCase { func testNullOptionsDecodes() { do { - let firstResident = try residentJSON.decode("residents", 0, alongPath: [.NullBecomesNil, .MissingKeyBecomesNil], type: Resident.self) + let firstResident = try residentJSON.decode(at: "residents", 0, alongPath: [.NullBecomesNil, .MissingKeyBecomesNil], type: Resident.self) XCTAssertNotNil(firstResident) } catch { XCTFail("There should be no error: \(error).") @@ -87,7 +87,7 @@ class JSONSubscriptingTests: XCTestCase { func testNullOptionsProducesOptionalForNotFoundWithArrayOf() { do { - let residents = try residentJSON.arrayOf("residents", type: Resident.self) + let residents = try residentJSON.decodedArray(at: "residents", type: Resident.self) XCTAssertNil(residents[1].age, "Drew's `age` should be nil.") } catch { XCTFail("There should be no error.") @@ -96,7 +96,7 @@ class JSONSubscriptingTests: XCTestCase { func testNullOptionsProducesOptionalForNotFoundWithDictionaryOf() { do { - let residents = try residentJSON.dictionaryOf("residentsByName", type: Resident.self) + let residents = try residentJSON.decodedDictionary(at: "residentsByName", type: Resident.self) XCTAssertNotNil(residents["Drew"]) XCTAssertNil(residents["Drew"]?.age, "Drew's `age` should be nil.") } catch { @@ -106,7 +106,7 @@ class JSONSubscriptingTests: XCTestCase { func testNullOptionsProducesOptionalForNullOrNotFoundWithArrayOf() { do { - let residents = try residentJSON.arrayOf("residents", type: Resident.self) + let residents = try residentJSON.decodedArray(at: "residents", type: Resident.self) XCTAssertNil(residents.first?.rent, "Matt should have nil `rent`.") XCTAssertEqual(residents[1].rent!, 1234.5, "Drew's `rent` should equal 1234.5.") XCTAssertNil(residents.last?.rent, "Pat should have nil `rent`.") @@ -117,7 +117,7 @@ class JSONSubscriptingTests: XCTestCase { func testNullOptionsProducesOptionalForNullOrNotFoundWithDictionaryOf() { do { - let residents = try residentJSON.dictionaryOf("residentsByName", type: Resident.self) + let residents = try residentJSON.decodedDictionary(at: "residentsByName", type: Resident.self) XCTAssertNotNil(residents["Matt"]) XCTAssertNil(residents["Matt"]?.rent, "Matt should have nil `rent`.") XCTAssertEqual(residents["Drew"]!.rent!, 1234.5, "Drew's `rent` should equal 1234.5.") @@ -130,7 +130,7 @@ class JSONSubscriptingTests: XCTestCase { func testNullOptionsIndexOutOfBoundsProducesOptional() { do { - let residentOutOfBounds = try residentJSON.decode("residents", 4, alongPath: .MissingKeyBecomesNil, type: Resident.self) + let residentOutOfBounds = try residentJSON.decode(at: "residents", 4, alongPath: .MissingKeyBecomesNil, type: Resident.self) XCTAssertNil(residentOutOfBounds) } catch { XCTFail("There should be no error: \(error).") @@ -138,11 +138,11 @@ class JSONSubscriptingTests: XCTestCase { } func testArrayOfJSONIntAndNullCreatesOptionalWhenDetectNull() { - let testJSON: JSON = [1,2,.Null,4] + let testJSON: JSON = [1,2,.null,4] do { - _ = try testJSON.arrayOf(alongPath: .NullBecomesNil, type: Int.self) + _ = try testJSON.decodedArray(alongPath: .NullBecomesNil, type: Int.self) XCTFail("`testJSON.arrayOf(_:options:type:)` should throw.") - } catch let JSON.Error.ValueNotConvertible(value, type) { + } catch let JSON.Error.valueNotConvertible(value, type) { XCTAssert(type == Int.self, "value (\(value)) is not equal to \(type).") } catch { XCTFail("There should be no error: \(error)") @@ -150,10 +150,10 @@ class JSONSubscriptingTests: XCTestCase { } func testArrayProducesOptionalWhenNotFoundOrNull() { - let testJSON: JSON = ["integers": .Null] + let testJSON: JSON = ["integers": .null] do { - let test1 = try testJSON.array("integers", alongPath: .NullBecomesNil) - let test2 = try testJSON.array("residents", alongPath: .MissingKeyBecomesNil) + let test1 = try testJSON.getArray(at: "integers", alongPath: .NullBecomesNil) + let test2 = try testJSON.getArray(at: "residents", alongPath: .MissingKeyBecomesNil) XCTAssertNil(test1, "Test1 should be nil.") XCTAssertNil(test2, "Test2 should be nil.") } catch { @@ -162,11 +162,11 @@ class JSONSubscriptingTests: XCTestCase { } func testDictionaryOfJSONIntAndNullCreatesOptionalWhenDetectNull() { - let testJSON: JSON = ["one": 1, "two": 2, "three": .Null, "four": 4] + let testJSON: JSON = ["one": 1, "two": 2, "three": .null, "four": 4] do { - _ = try testJSON.dictionaryOf(alongPath: .NullBecomesNil, type: Int.self) + _ = try testJSON.decodedDictionary(alongPath: .NullBecomesNil, type: Int.self) XCTFail("`testJSON.dictionaryOf(_:options:type:)` should throw.") - } catch let JSON.Error.ValueNotConvertible(value, type) { + } catch let JSON.Error.valueNotConvertible(value, type) { XCTAssert(type == Int.self, "value (\(value)) is not equal to \(type).") } catch { XCTFail("There should be no error: \(error)") @@ -174,10 +174,10 @@ class JSONSubscriptingTests: XCTestCase { } func testDictionaryProducesOptionalWhenNotFoundOrNull() { - let testJSON: JSON = ["integers": .Null] + let testJSON: JSON = ["integers": .null] do { - let test1 = try testJSON.dictionary("integers", alongPath: .NullBecomesNil) - let test2 = try testJSON.dictionary("residents", alongPath: .MissingKeyBecomesNil) + let test1 = try testJSON.getDictionary(at: "integers", alongPath: .NullBecomesNil) + let test2 = try testJSON.getDictionary(at: "residents", alongPath: .MissingKeyBecomesNil) XCTAssertNil(test1, "Test1 should be nil.") XCTAssertNil(test2, "Test2 should be nil.") } catch { @@ -186,7 +186,7 @@ class JSONSubscriptingTests: XCTestCase { } func testDecodeNullBecomesNilProducesOptional() { - let json: JSON = ["type": "Apartment", "resident": .Null] + let json: JSON = ["type": "Apartment", "resident": .null] do { let apartment = try json.decode(alongPath: .NullBecomesNil, type: Apartment.self) XCTAssertNil(apartment?.resident, "This resident should be nil!") @@ -197,9 +197,9 @@ class JSONSubscriptingTests: XCTestCase { func testJSONDictionaryUnexpectedSubscript() { do { - _ = try residentJSON.decode(1, type: Resident.self) + _ = try residentJSON.decode(at: 1, type: Resident.self) XCTFail("Should throw error.") - } catch JSON.Error.UnexpectedSubscript(type: let theType) { + } catch JSON.Error.unexpectedSubscript(type: let theType) { XCTAssertTrue(theType is Int.Type) } catch { XCTFail("Didn't catch the right error: \(error).") @@ -218,7 +218,7 @@ class JSONSubscriptingTests: XCTestCase { func testDecodeOr() { do { - let outOfBounds = try residentJSON.decode("residents", 4, or: Resident(name: "NA", age: 30, hasPet: false, rent: 0)) + let outOfBounds = try residentJSON.decode(at: "residents", 4, or: Resident(name: "NA", age: 30, hasPet: false, rent: 0)) XCTAssertTrue(outOfBounds.name == "NA") } catch { XCTFail("There should be no error: \(error).") @@ -227,7 +227,7 @@ class JSONSubscriptingTests: XCTestCase { func testDoubleOr() { do { - let rent = try residentJSON.double("residents", 2, "rent", or: 0) + let rent = try residentJSON.getDouble(at: "residents", 2, "rent", or: 0) XCTAssertTrue(rent == 0, "Rent should be free.") } catch { XCTFail("There should be no error: \(error).") @@ -236,7 +236,7 @@ class JSONSubscriptingTests: XCTestCase { func testStringOr() { do { - let nickname = try residentJSON.string("residents", 0, "nickname", or: "DubbaDubs") + let nickname = try residentJSON.getString(at: "residents", 0, "nickname", or: "DubbaDubs") XCTAssertTrue(nickname == "DubbaDubs") } catch { XCTFail("There should be no error: \(error).") @@ -245,7 +245,7 @@ class JSONSubscriptingTests: XCTestCase { func testIntOr() { do { - let age = try residentJSON.int("residents", 1, "age", or: 21) + let age = try residentJSON.getInt(at: "residents", 1, "age", or: 21) XCTAssertTrue(age == 21, "Forever young!") } catch { XCTFail("There should be no error: \(error).") @@ -254,7 +254,7 @@ class JSONSubscriptingTests: XCTestCase { func testBoolOr() { do { - let hasSpouse = try residentJSON.bool("residents", 1, "hasSpouse", or: false) + let hasSpouse = try residentJSON.getBool(at: "residents", 1, "hasSpouse", or: false) XCTAssertFalse(hasSpouse, "No spouse") } catch { XCTFail("There should be no error: \(error).") @@ -263,9 +263,9 @@ class JSONSubscriptingTests: XCTestCase { func testArrayOr() { do { - let testJSON: JSON = ["pets": .Null] + let testJSON: JSON = ["pets": .null] let defaultArrayOfJSON: [JSON] = ["Oink", "Snuggles"] - let pets = try testJSON.array("pet", or: defaultArrayOfJSON) + let pets = try testJSON.getArray(at: "pet", or: defaultArrayOfJSON) XCTAssertEqual(pets, defaultArrayOfJSON, "`pets` should equal the `defaultArrayOfJSON`.") } catch { XCTFail("There should be no error: \(error).") @@ -275,7 +275,7 @@ class JSONSubscriptingTests: XCTestCase { func testArrayOfOr() { do { let matt = Resident(name: "Matt", age: 32, hasPet: false, rent: 500.00) - let residentsOr = try residentJSON.arrayOf("residnts", or: [matt]) + let residentsOr = try residentJSON.decodedArray(at: "residnts", or: [matt]) XCTAssertEqual(residentsOr.first!, matt, "`residents` should not be nil") } catch { XCTFail("There should be no error: \(error).") @@ -284,8 +284,8 @@ class JSONSubscriptingTests: XCTestCase { func testDictionaryOr() { do { - let jsonDict: [String: JSON] = ["name": "Matt", "age": 33, "hasPet": false, "rent": .Null] - let mattOr = try residentJSON.dictionary("residents", 4, or: jsonDict) + let jsonDict: [String: JSON] = ["name": "Matt", "age": 33, "hasPet": false, "rent": .null] + let mattOr = try residentJSON.getDictionary(at: "residents", 4, or: jsonDict) XCTAssertEqual(jsonDict, mattOr, "`jsonDict` should equal `mattOr`") } catch { XCTFail("There should be no error: \(error).") @@ -295,7 +295,7 @@ class JSONSubscriptingTests: XCTestCase { func testDictionaryOfOr() { do { let matt = Resident(name: "Matt", age: 32, hasPet: false, rent: 500.00) - let residentsOr = try residentJSON.dictionaryOf("residnts", or: ["Matt": matt]) + let residentsOr = try residentJSON.decodedDictionary(at: "residnts", or: ["Matt": matt]) XCTAssertEqual(residentsOr, ["Matt": matt], "`residents` should not be nil") } catch { XCTFail("There should be no error: \(error).") @@ -304,8 +304,8 @@ class JSONSubscriptingTests: XCTestCase { func testThatUnexpectedSubscriptIsThrown() { do { - _ = try residentJSON.decode("residents", 1, "name", "initial", type: Resident.self) - } catch JSON.Error.UnexpectedSubscript(let type) { + _ = try residentJSON.decode(at: "residents", 1, "name", "initial", type: Resident.self) + } catch JSON.Error.unexpectedSubscript(let type) { XCTAssert(type == Swift.String, "The dictionary at index 1 should not be subscriptable by: \(type).") } catch { XCTFail("This should not be: \(error).") @@ -314,7 +314,7 @@ class JSONSubscriptingTests: XCTestCase { func testMissingKeyOptionStillFailsIfNullEncountered() { do { - let json = JSON.Dictionary([ + let json = JSON.dictionary([ "name": "Drew", "age": nil, // should cause problems! "hasPet": true, @@ -322,7 +322,7 @@ class JSONSubscriptingTests: XCTestCase { ]) let resident = try Resident(json: json) XCTFail("Unexpected success: \(resident)") - } catch let JSON.Error.ValueNotConvertible(value: value, to: type) { + } catch let JSON.Error.valueNotConvertible(value: value, to: type) { XCTAssert(type == Int.self, "unexpected type \(type) of value \(value)") } catch { XCTFail("Unexpected error: \(error)") @@ -331,13 +331,13 @@ class JSONSubscriptingTests: XCTestCase { func testSubscriptingOptionsStillFailIfKeyIsMissing() { do { - let json = JSON.Dictionary([ + let json = JSON.dictionary([ "name": "Drew", "rent": 1234.5, ]) let resident = try Resident(json: json) XCTFail("Unexpected success: \(resident)") - } catch let JSON.Error.KeyNotFound(key: key) where key == "hasPet" { + } catch let JSON.Error.keyNotFound(key: key) where key == "hasPet" { // expected } catch { XCTFail("Unexpected error: \(error)") @@ -345,7 +345,7 @@ class JSONSubscriptingTests: XCTestCase { } func testThatMapCanCreateArrayOfPeople() { - let peopleJSON = try! json.array("people") + let peopleJSON = try! json.getArray(at: "people") let people = try! peopleJSON.map(Person.init) for person in people { XCTAssertNotEqual(person.name, "", "There should be a name.") @@ -353,25 +353,25 @@ class JSONSubscriptingTests: XCTestCase { } func testThatSubscriptingJSONWorksForTopLevelObject() { - let success = try? json.bool("success") + let success = try? json.getBool(at: "success") XCTAssertEqual(success, true, "There should be `success`.") } func testThatPathSubscriptingPerformsNesting() { - for z in try! json.array("states", "Georgia") { - XCTAssertNotNil(try? z.int(), "The `Int` should not be `nil`.") + for z in try! json.getArray(at: "states", "Georgia") { + XCTAssertNotNil(try? z.getInt(), "The `Int` should not be `nil`.") } } func testJSONSubscriptWithInt() { - let mattmatt = try? json.string("people", 0, "name") + let mattmatt = try? json.getString(at: "people", 0, "name") XCTAssertEqual(mattmatt, "Matt Mathias", "`matt` should hold string `Matt Mathias`") } func testJSONErrorKeyNotFound() { do { - _ = try json.array("peopl") - } catch JSON.Error.KeyNotFound(let key) { + _ = try json.getArray(at: "peopl") + } catch JSON.Error.keyNotFound(let key) { XCTAssert(key == "peopl", "The error should be due to the key not being found.") } catch { XCTFail("The error should be due to the key not being found, but was: \(error).") @@ -380,8 +380,8 @@ class JSONSubscriptingTests: XCTestCase { func testJSONErrorIndexOutOfBounds() { do { - _ = try json.dictionary("people", 4) - } catch JSON.Error.IndexOutOfBounds(let index) { + _ = try json.getDictionary(at: "people", 4) + } catch JSON.Error.indexOutOfBounds(let index) { XCTAssert(index == 4, "The error should be due to the index being out of bounds.") } catch { XCTFail("The error should be due to the index being out of bounds, but was: \(error).") @@ -390,8 +390,8 @@ class JSONSubscriptingTests: XCTestCase { func testJSONErrorTypeNotConvertible() { do { - _ = try json.int("people", 0, "name") - } catch let JSON.Error.ValueNotConvertible(value, to) { + _ = try json.getInt(at: "people", 0, "name") + } catch let JSON.Error.valueNotConvertible(value, to) { XCTAssert(to == Swift.Int, "The error should be due the value not being an `Int` case, but was \(to).") XCTAssert(value == "Matt Mathias", "The error should be due the value being the String 'Matt Mathias', but was \(value).") } catch { @@ -401,8 +401,8 @@ class JSONSubscriptingTests: XCTestCase { func testJSONErrorUnexpectedSubscript() { do { - _ = try json.string("people", "name") - } catch JSON.Error.UnexpectedSubscript(let type) { + _ = try json.getString(at: "people", "name") + } catch JSON.Error.unexpectedSubscript(let type) { XCTAssert(type == Swift.String, "The error should be due the value not being subscriptable with string `String` case, but was \(type).") } catch { XCTFail("The error should be due to the `people` `Array` not being subscriptable with `String`s, but was: \(error).") @@ -410,14 +410,14 @@ class JSONSubscriptingTests: XCTestCase { } func testThatOptionalSubscriptingIntoNullSucceeds() { - let earlyNull = [ "foo": nil ] as JSON - let string = try! earlyNull.string("foo", "bar", "baz", alongPath: .NullBecomesNil) + let earlyNull = ["foo": nil] as JSON + let string = try! earlyNull.getString(at: "foo", "bar", "baz", alongPath: .NullBecomesNil) XCTAssertNil(string) } func testThatOptionalSubscriptingKeyNotFoundSucceeds() { - let keyNotFound = [ "foo": 2 ] as JSON - let string = try! keyNotFound.string("bar", alongPath: .MissingKeyBecomesNil) + let keyNotFound = ["foo": 2] as JSON + let string = try! keyNotFound.getString(at: "bar", alongPath: .MissingKeyBecomesNil) XCTAssertNil(string) } @@ -431,11 +431,11 @@ private struct Resident { } extension Resident: JSONDecodable { - private init(json: JSON) throws { - name = try json.string("name") - age = try json.int("age", alongPath: .MissingKeyBecomesNil) - hasPet = try json.bool("hasPet", alongPath: .NullBecomesNil) - rent = try json.double("rent", alongPath: [.NullBecomesNil, .MissingKeyBecomesNil]) + fileprivate init(json: JSON) throws { + name = try json.getString(at: "name") + age = try json.getInt(at: "age", alongPath: .MissingKeyBecomesNil) + hasPet = try json.getBool(at: "hasPet", alongPath: .NullBecomesNil) + rent = try json.getDouble(at: "rent", alongPath: [.NullBecomesNil, .MissingKeyBecomesNil]) } } @@ -445,9 +445,9 @@ private struct Apartment { } extension Apartment: JSONDecodable { - private init(json: JSON) throws { - type = try json.string("type") - resident = try json.decode("resident", alongPath: .NullBecomesNil, type: Resident.self) + fileprivate init(json: JSON) throws { + type = try json.getString(at: "type") + resident = try json.decode(at: "resident", alongPath: .NullBecomesNil, type: Resident.self) } } @@ -463,34 +463,34 @@ private func ==(lhs: Resident, rhs: Resident) -> Bool { class JSONSubscriptWithNSJSONTests: JSONSubscriptingTests { override func parser() -> JSONParserType.Type { - return NSJSONSerialization.self + return JSONSerialization.self } } // Just for syntax validation, not for execution or being counted for coverage. private func testUsage() { - let j = JSON.Null + let j = JSON.null - _ = try? j.int() - _ = try? j.int(alongPath: .MissingKeyBecomesNil) - _ = try? j.int(alongPath: .NullBecomesNil) - _ = try? j.int(or: 42) + _ = try? j.getInt() + _ = try? j.getInt(alongPath: .MissingKeyBecomesNil) + _ = try? j.getInt(alongPath: .NullBecomesNil) + _ = try? j.getInt(or: 42) - _ = try? j.int("key") - _ = try? j.int("key", alongPath: .MissingKeyBecomesNil) - _ = try? j.int("key", alongPath: .NullBecomesNil) - _ = try? j.int("key", or: 42) + _ = try? j.getInt(at: "key") + _ = try? j.getInt(at: "key", alongPath: .MissingKeyBecomesNil) + _ = try? j.getInt(at: "key", alongPath: .NullBecomesNil) + _ = try? j.getInt(at: "key", or: 42) - _ = try? j.int(1) - _ = try? j.int(2, alongPath: .MissingKeyBecomesNil) - _ = try? j.int(3, alongPath: .NullBecomesNil) - _ = try? j.int(4, or: 42) + _ = try? j.getInt(at: 1) + _ = try? j.getInt(at: 2, alongPath: .MissingKeyBecomesNil) + _ = try? j.getInt(at: 3, alongPath: .NullBecomesNil) + _ = try? j.getInt(at: 4, or: 42) let stringConst = "key" - _ = try? j.int(stringConst, 1) - _ = try? j.int(stringConst, 2, alongPath: .MissingKeyBecomesNil) - _ = try? j.int(stringConst, 3, alongPath: .NullBecomesNil) - _ = try? j.int(stringConst, 4, or: 42) + _ = try? j.getInt(at: stringConst, 1) + _ = try? j.getInt(at: stringConst, 2, alongPath: .MissingKeyBecomesNil) + _ = try? j.getInt(at: stringConst, 3, alongPath: .NullBecomesNil) + _ = try? j.getInt(at: stringConst, 4, or: 42) } diff --git a/Tests/JSONTests.swift b/Tests/JSONTests.swift index 46099f94..25666bb8 100644 --- a/Tests/JSONTests.swift +++ b/Tests/JSONTests.swift @@ -11,17 +11,17 @@ import Freddy class JSONTests: XCTestCase { - var sampleData:NSData! + var sampleData:Data! override func setUp() { super.setUp() - let testBundle = NSBundle(forClass: JSONSubscriptingTests.self) - guard let data = testBundle.URLForResource("sample", withExtension: "JSON").flatMap(NSData.init) else { + let testBundle = Bundle(for: JSONSubscriptingTests.self) + guard let data = testBundle.url(forResource: "sample", withExtension: "JSON").flatMap(NSData.init(contentsOf:)) else { XCTFail("Could not read sample data from test bundle") return } - sampleData = data + sampleData = data as Data } func testInitializingFromData() { @@ -38,7 +38,7 @@ class JSONTests: XCTestCase { func DoNotRuntestInitializingFromEmptyData() { do { - _ = try JSON(data: NSData()) + _ = try JSON(data: Data()) } catch { XCTFail("Could not parse empty data: \(error)") return @@ -67,4 +67,4 @@ class JSONTests: XCTestCase { return } } -} \ No newline at end of file +} diff --git a/Tests/JSONTypeTests.swift b/Tests/JSONTypeTests.swift index 9b0dd20a..f3efe207 100644 --- a/Tests/JSONTypeTests.swift +++ b/Tests/JSONTypeTests.swift @@ -12,71 +12,71 @@ import Freddy class JSONTypeTests: XCTestCase { func testCastInitializeArray() { - let array = [ JSON.Int(1), JSON.Int(2), JSON.Int(3) ] - let expected = JSON.Array(array) + let array: [JSON] = [1, 2, 3] + let expected = JSON.array(array) let json = JSON(array) XCTAssertEqual(json, expected) } func testCastInitializeAnyCollection() { - let collection = (1 ... 3).lazy.map { JSON.Int($0) } - let expected = JSON.Array([ JSON.Int(1), JSON.Int(2), JSON.Int(3) ]) + let collection = (1 ... 3).lazy.map { JSON.int($0) } + let expected: JSON = .array([1, 2, 3]) let json = JSON(collection) XCTAssertEqual(json, expected) } func testCastInitializeDictionary() { - let dictionary = [ "foo": JSON.Int(1), "bar": JSON.Int(2), "baz": JSON.Int(3) ] - let expected = JSON.Dictionary(dictionary) + let dictionary: [String:JSON] = ["foo": 1, "bar": 2, "baz": 3] + let expected = JSON.dictionary(dictionary) let json = JSON(dictionary) XCTAssertEqual(json, expected) } func testCastInitializeAnyDictionary() { - let dictionary = [ "foo": 1, "bar": 2, "baz": 3 ] + let dictionary = ["foo": 1, "bar": 2, "baz": 3] let pairCollection = dictionary.lazy.map { (key, value) in (key, JSON(value * 2)) } - let expected = JSON.Dictionary([ "foo": JSON.Int(2), "bar": JSON.Int(4), "baz": JSON.Int(6) ]) + let expected: JSON = .dictionary(["foo": 2, "bar": 4, "baz": 6]) let json = JSON(pairCollection) XCTAssertEqual(json, expected) } func testCastInitializeDouble() { let double = 42.0 as Double - let expected = JSON.Double(double) + let expected = JSON.double(double) let json = JSON(double) XCTAssertEqual(json, expected) } func testCastInitializeInt() { let int = 65535 as Int - let expected = JSON.Int(int) + let expected = JSON.int(int) let json = JSON(int) XCTAssertEqual(json, expected) } func testCastInitializeString() { let string = "Don't Panic" - let expected = JSON.String(string) + let expected = JSON.string(string) let json = JSON(string) XCTAssertEqual(json, expected) } func testCastInitializeBool() { let bool = false - let expected = JSON.Bool(bool) + let expected = JSON.bool(bool) let json = JSON(bool) XCTAssertEqual(json, expected) } func testLiteralConversion() { - let valueNotLiteral: JSON = .Dictionary([ - "someKey": .Array([ - .Dictionary([ "children": .Array([ .String("a string") ]) ]), - .Dictionary([ "children": .Array([ .String("\u{00E9}"), .String("\u{00E9}") ]) ]), - .Dictionary([ "children": .Array([ .String("\u{1F419}"), .String("\u{1F419}") ]) ]), - .Dictionary([ "children": .Array([ .Double(42.0), .Int(65535), .Bool(true), .Null ]) ]) + let valueNotLiteral: JSON = .dictionary([ + "someKey": .array([ + .dictionary([ "children": .array([ .string("a string") ]) ]), + .dictionary([ "children": .array([ .string("\u{00E9}"), .string("\u{00E9}") ]) ]), + .dictionary([ "children": .array([ .string("\u{1F419}"), .string("\u{1F419}") ]) ]), + .dictionary([ "children": .array([ .double(42.0), .int(65535), .bool(true), .null ]) ]) ]) ]) diff --git a/Tests/Person.swift b/Tests/Person.swift index ccc89215..82e43631 100644 --- a/Tests/Person.swift +++ b/Tests/Person.swift @@ -30,15 +30,15 @@ extension Person.EyeColor: JSONEncodable {} extension Person: JSONDecodable { public init(json value: JSON) throws { - name = try value.string("name") - age = try value.int("age") - eyeColor = try value.decode("eyeColor") - spouse = try value.bool("spouse") + name = try value.getString(at: "name") + age = try value.getInt(at: "age") + eyeColor = try value.decode(at: "eyeColor") + spouse = try value.getBool(at: "spouse") } } extension Person: JSONEncodable { public func toJSON() -> JSON { - return .Dictionary(["name": .String(name), "age": .Int(age), "eyeColor": eyeColor.toJSON(), "spouse": .Bool(spouse)]) + return .dictionary(["name": .string(name), "age": .int(age), "eyeColor": eyeColor.toJSON(), "spouse": .bool(spouse)]) } } diff --git a/fastlane/Fastfile b/fastlane/Fastfile new file mode 100644 index 00000000..e4de8601 --- /dev/null +++ b/fastlane/Fastfile @@ -0,0 +1,69 @@ +opt_out_usage + +####################################################################### +# Lifecycle Hooks +####################################################################### + +before_all do + reset_simulators +end + +after_all do |lane| + # This block is called, only if the executed lane was successful +end + +error do |lane, exception| +end + +####################################################################### +# Lanes +####################################################################### + +desc "Perform the build steps on travis CI" +lane :travis do + macOS + iOS + tvOS + validate_cocoapods + validate_carthage +end + +desc "Build Freddy for macOS" +lane :macOS do + scan(scheme: "Freddy") +end + +desc "Build Freddy for iOS" +lane :iOS do + scan(scheme: "MobileFreddy", device: "iPhone 7 (10.0)") +end + +desc "Build Freddy for tvOS" +lane :tvOS do + scan(scheme: "TVFreddy") +end + +desc "Validate cocoapods podspec file" +lane :validate_cocoapods do + pod_lib_lint(quick: true) +end + +desc "Validate carthage build" +lane :validate_carthage do + if is_ci? + system("./Resources/scripts/validate_carthage.sh") + else + puts "This is a CI only lane, skipping" + end +end + +desc "Create docs" +lane :create_docs do + ## TODO: Implement once jazzy is working well for Xcode 8 + if is_ci? + #system("./Resources/scripts/publish_docs.sh") + puts "Would be creating docs here" + else + puts "This is a CI only lane, skipping" + end +end diff --git a/fastlane/README.md b/fastlane/README.md new file mode 100644 index 00000000..e16f5c8a --- /dev/null +++ b/fastlane/README.md @@ -0,0 +1,48 @@ +fastlane documentation +================ +# Installation +``` +sudo gem install fastlane +``` +# Available Actions +### travis +``` +fastlane travis +``` +Perform the build steps on travis CI +### macOS +``` +fastlane macOS +``` +Build Freddy for macOS +### iOS +``` +fastlane iOS +``` +Build Freddy for iOS +### tvOS +``` +fastlane tvOS +``` +Build Freddy for tvOS +### validate_cocoapods +``` +fastlane validate_cocoapods +``` +Validate cocoapods podspec file +### validate_carthage +``` +fastlane validate_carthage +``` +Validate carthage build +### create_docs +``` +fastlane create_docs +``` +Create docs + +---- + +This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run. +More information about fastlane can be found on [https://fastlane.tools](https://fastlane.tools). +The documentation of fastlane can be found on [GitHub](https://github.com/fastlane/fastlane/tree/master/fastlane). \ No newline at end of file