├── .gitignore
├── Cartfile
├── Cartfile.resolved
├── Carthage
└── Checkouts
│ └── VinceRP
│ ├── .gitignore
│ ├── .gitmodules
│ ├── .travis.yml
│ ├── CONTRIBUTING.md
│ ├── Cartfile.private
│ ├── Cartfile.resolved
│ ├── LICENSE
│ ├── README.md
│ ├── VinceRP.podspec
│ ├── examples
│ ├── BasicExample.xcodeproj
│ │ ├── project.pbxproj
│ │ └── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ ├── BasicExample
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── flickr-icon.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── flickr-icon-1.png
│ │ │ │ ├── flickr-icon.png
│ │ │ │ └── flickr-icon@3x.png
│ │ │ └── login-icon.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ ├── login-icon.png
│ │ │ │ ├── login-icon@2x.png
│ │ │ │ └── login-icon@3x.png
│ │ ├── Base.lproj
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── FlickrPhotoCell.swift
│ │ ├── FlickrService.swift
│ │ ├── FlickrViewController.swift
│ │ ├── Info.plist
│ │ ├── LoginService.swift
│ │ ├── LoginViewControler.swift
│ │ └── UIImage+FromColor.swift
│ ├── Cartfile
│ └── Cartfile.resolved
│ ├── logoTrimmed.png
│ ├── performance
│ ├── Cartfile
│ ├── Cartfile.resolved
│ ├── Performance.xcodeproj
│ │ ├── project.pbxproj
│ │ └── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ ├── Performance
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ │ └── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ ├── Base.lproj
│ │ │ └── MainMenu.xib
│ │ └── Info.plist
│ └── PerformanceTests
│ │ ├── Info.plist
│ │ └── PerformanceTests.swift
│ ├── scripts
│ ├── test.sh
│ └── unstash.sh
│ ├── vincerp.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ ├── VinceRP-Mac.xcscheme
│ │ └── vincerp.xcscheme
│ ├── vincerp.xcworkspace
│ └── xcshareddata
│ │ └── WorkspaceSettings.xcsettings
│ ├── vincerp
│ ├── Common
│ │ ├── Api.swift
│ │ ├── Convenient
│ │ │ └── Addable.swift
│ │ ├── Core
│ │ │ ├── BatchUpdate.swift
│ │ │ ├── ChangeObserver.swift
│ │ │ ├── Dynamic.swift
│ │ │ ├── ErrorObserver.swift
│ │ │ ├── Hub+operators.swift
│ │ │ ├── Hub.swift
│ │ │ ├── Incrementing.swift
│ │ │ ├── Mapper.swift
│ │ │ ├── Node.swift
│ │ │ ├── NodeTuple.swift
│ │ │ ├── Propagator.swift
│ │ │ ├── Reducer.swift
│ │ │ ├── Source.swift
│ │ │ ├── Throttle.swift
│ │ │ └── Wrapper.swift
│ │ ├── Threading
│ │ │ ├── AtomicLong.swift
│ │ │ ├── AtomicReference.swift
│ │ │ ├── Dispatchable.swift
│ │ │ ├── DynamicVariable.swift
│ │ │ ├── Spinlock.swift
│ │ │ └── ThreadLocal.swift
│ │ ├── Timer.swift
│ │ └── Util
│ │ │ ├── CommonConstants.swift
│ │ │ ├── ExceptionHandling.swift
│ │ │ ├── Flattenable.swift
│ │ │ ├── FunctionalArray.swift
│ │ │ ├── FunctionalDictionary.swift
│ │ │ ├── FunctionalSet.swift
│ │ │ ├── ReactivePropertyGenerator.swift
│ │ │ ├── Try.swift
│ │ │ ├── VRPNSObjectHelper.h
│ │ │ ├── VRPNSObjectHelper.m
│ │ │ ├── WeakReference.swift
│ │ │ └── WeakSet.swift
│ ├── Extension
│ │ ├── AppKit
│ │ │ ├── NSResponder+VinceRP.swift
│ │ │ ├── NSTextField+VinceRP.swift
│ │ │ ├── NSTextField+didChange.swift
│ │ │ └── NSView+VinceRP.swift
│ │ ├── Common
│ │ │ ├── Foundation
│ │ │ │ └── String+vincerp.swift
│ │ │ └── NSObject+vincerp.swift
│ │ └── UIKit
│ │ │ ├── UIActivityIndicatorView+vincerp.swift
│ │ │ ├── UIButton+vincerp.swift
│ │ │ ├── UIControl+vincerp.swift
│ │ │ ├── UILabel+vincerp.swift
│ │ │ ├── UIResponder+vincerp.swift
│ │ │ ├── UISearchBar+didChange.swift
│ │ │ ├── UISearchBar+vincerp.swift
│ │ │ ├── UIStepper+vincerp.swift
│ │ │ ├── UITextField+didChange.swift
│ │ │ ├── UITextField+vincerp.swift
│ │ │ └── UIView+vincerp.swift
│ ├── Info.plist
│ ├── UpdateState.swift
│ └── vincerp.h
│ └── vincerpTests
│ ├── Common
│ ├── AdvancedSpec.swift
│ ├── BasicSpec.swift
│ ├── Core
│ │ ├── Hub+operatorsSpec.swift
│ │ ├── MapperSpec.swift
│ │ ├── ReducerSpec.swift
│ │ └── ThrottleSpec.swift
│ ├── SmokeSpec.swift
│ ├── Threading
│ │ └── DynamicVariableSpec.swift
│ └── Util
│ │ ├── FunctionalArraySpec.swift
│ │ ├── FunctionalDictionarySpec.swift
│ │ ├── FunctionalSetSpec.swift
│ │ ├── TrySpec.swift
│ │ └── WeakReferenceTests.swift
│ ├── Info.plist
│ └── TestUtil.swift
├── CopyPasta.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcshareddata
│ └── xcschemes
│ │ └── CopyPasta.xcscheme
└── xcuserdata
│ └── vasarhelyia.xcuserdatad
│ ├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ └── xcschememanagement.plist
├── CopyPasta
├── AppDelegate.swift
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ └── pasta_icon.imageset
│ │ ├── Contents.json
│ │ └── pasta_icon.png
├── ImageItemCell.xib
├── Info.plist
├── MainMenu.xib
├── MainViewController.swift
├── MainViewController.xib
├── PastePopoverBackgroundView.swift
├── PasteViewModel.swift
├── PasteboardCollectionViewItem.swift
├── PasteboardItem.swift
├── PasteboardService.swift
├── PasteboardViewController.swift
├── PasteboardViewController.xib
├── TextItemCell.xib
└── View
│ └── Popover
│ └── PastePopoverRootView.swift
├── CopyPastaTests
├── Info.plist
├── PasteViewModelTests.swift
├── PasteboardItemTests.swift
├── PasteboardPollingTests.swift
└── PasteboardServiceTests.swift
├── LICENSE
├── README.md
└── bitrise.yml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | build/
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | *.xccheckout
13 | *.moved-aside
14 | DerivedData
15 | *.hmap
16 | *.ipa
17 | *.xcuserstate
18 |
19 | # CocoaPods
20 | #
21 | # We recommend against adding the Pods directory to your .gitignore. However
22 | # you should judge for yourself, the pros and cons are mentioned at:
23 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
24 | #
25 | # Pods/
26 |
27 | # Carthage
28 | #
29 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
30 | # Carthage/Checkouts
31 |
32 | Carthage/Build
33 |
--------------------------------------------------------------------------------
/Cartfile:
--------------------------------------------------------------------------------
1 | github "bvic23/VinceRP" "v0.2.5"
2 |
--------------------------------------------------------------------------------
/Cartfile.resolved:
--------------------------------------------------------------------------------
1 | github "bvic23/VinceRP" "v0.2.5"
2 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #-------
3 | .DS_Store
4 |
5 | # XCode
6 | #-------
7 | *.pbxuser
8 | *.mode1v3
9 | *.mode2v3
10 | *.perspectivev3
11 | xcuserdata
12 | */build/*
13 | profile
14 | *.moved-aside
15 | DerivedData
16 | Build
17 | *.hmap
18 | *.xccheckout
19 | !default.pbxuser
20 | !default.mode1v3
21 | !default.mode2v3
22 | !default.perspectivev3
23 |
24 | # AppCode
25 | #-------
26 | .idea
27 |
28 | # Carthage
29 | #---------
30 | Carthage
31 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "Carthage/Checkouts/Nimble"]
2 | path = Carthage/Checkouts/Nimble
3 | url = https://github.com/Quick/Nimble.git
4 | [submodule "Carthage/Checkouts/Quick"]
5 | path = Carthage/Checkouts/Quick
6 | url = https://github.com/Quick/Quick.git
7 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | osx_image: xcode7.1
3 | before_install:
4 | - gem install xcpretty --no-rdoc --no-ri --no-document --quiet
5 | - gem install xcpretty-travis-formatter --no-rdoc --no-ri --no-document --quiet
6 | - ./scripts/unstash.sh
7 | install:
8 | - set -o pipefail && xcodebuild clean build test -project VinceRP.xcodeproj -scheme VinceRP-Mac -sdk macosx -enableCodeCoverage YES ONLY_ACTIVE_ARCH=NO GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO | xcpretty -c -f `xcpretty-travis-formatter`
9 | env:
10 | global:
11 | - LANG=en_US.UTF-8
12 | - LC_ALL=en_US.UTF-8
13 | branches:
14 | only:
15 | - master
16 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribution Guidelines
2 |
3 | ## General Guidelines
4 |
5 | - **Min iOS SDK**: 7.0
6 | - **Min OSX SDK**: 10.9
7 | - **Language**: Swift 2.0
8 | - **Tests**: Yes, please using [Quick](https://github.com/Quick/Quick)
9 |
10 | ## Style Guide
11 |
12 | #### Base style:
13 |
14 | Please add new code to this project based on the following style guideline:
15 |
16 | - [The official Swift style guide for raywenderlich.com.](https://github.com/raywenderlich/swift-style-guide)
17 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/Cartfile.private:
--------------------------------------------------------------------------------
1 | github "Quick/Quick" "HEAD"
2 | github "Quick/Nimble" "HEAD"
3 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/Cartfile.resolved:
--------------------------------------------------------------------------------
1 | github "Quick/Nimble" "c2aafa5da886f4e44ee29b4faaaa20fdac8a9369"
2 | github "Quick/Quick" "5fff1989f54b73f9d51725727e04aafb9557b41e"
3 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright © 2015 bvic23
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/VinceRP.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 |
3 | s.name = 'VinceRP'
4 | s.version = '0.2.4'
5 | s.summary = 'Easy to use, easy to extend reactive framework for Swift.'
6 |
7 | s.description = <<-DESC
8 | Easy to use, easy to extend reactive framework for Swift. If you are bored of doing MVC over and over give VinceRP a try.
9 | DESC
10 |
11 | s.homepage = 'https://github.com/bvic23/VinceRP'
12 | s.license = { :type => 'MIT', :file => 'LICENSE' }
13 |
14 | s.author = { 'bvic23' => 'bvic23@gmail.com' }
15 | s.social_media_url = 'http://twitter.com/bvic23'
16 | s.platform = :ios, :osx
17 |
18 | s.source = { :git => 'https://github.com/bvic23/VinceRP.git', :tag => s.version.to_s }
19 |
20 | s.source_files = 'VinceRP/Common/**/*.{swift,h,m}', 'VinceRP/Extension/Common/**/*.{swift}'
21 |
22 | s.ios.deployment_target = '8.0'
23 | s.ios.source_files = 'VinceRP/Extension/UIKit/*.{swift}',
24 |
25 | s.osx.deployment_target = '10.10'
26 | s.osx.source_files = 'VinceRP/Extension/AppKit/*.{swift}'
27 |
28 | end
29 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 05/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | @UIApplicationMain
9 | class AppDelegate: UIResponder, UIApplicationDelegate {
10 |
11 | var window: UIWindow?
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/Assets.xcassets/flickr-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "flickr-icon.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "flickr-icon-1.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "flickr-icon@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/Assets.xcassets/flickr-icon.imageset/flickr-icon-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alltheflow/CopyPasta/79460ff452600945de8c7ef1560c948dfe7b6942/Carthage/Checkouts/VinceRP/examples/BasicExample/Assets.xcassets/flickr-icon.imageset/flickr-icon-1.png
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/Assets.xcassets/flickr-icon.imageset/flickr-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alltheflow/CopyPasta/79460ff452600945de8c7ef1560c948dfe7b6942/Carthage/Checkouts/VinceRP/examples/BasicExample/Assets.xcassets/flickr-icon.imageset/flickr-icon.png
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/Assets.xcassets/flickr-icon.imageset/flickr-icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alltheflow/CopyPasta/79460ff452600945de8c7ef1560c948dfe7b6942/Carthage/Checkouts/VinceRP/examples/BasicExample/Assets.xcassets/flickr-icon.imageset/flickr-icon@3x.png
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/Assets.xcassets/login-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "login-icon.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "login-icon@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "login-icon@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/Assets.xcassets/login-icon.imageset/login-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alltheflow/CopyPasta/79460ff452600945de8c7ef1560c948dfe7b6942/Carthage/Checkouts/VinceRP/examples/BasicExample/Assets.xcassets/login-icon.imageset/login-icon.png
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/Assets.xcassets/login-icon.imageset/login-icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alltheflow/CopyPasta/79460ff452600945de8c7ef1560c948dfe7b6942/Carthage/Checkouts/VinceRP/examples/BasicExample/Assets.xcassets/login-icon.imageset/login-icon@2x.png
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/Assets.xcassets/login-icon.imageset/login-icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alltheflow/CopyPasta/79460ff452600945de8c7ef1560c948dfe7b6942/Carthage/Checkouts/VinceRP/examples/BasicExample/Assets.xcassets/login-icon.imageset/login-icon@3x.png
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/FlickrPhotoCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 05/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | class FlickrPhotoCell: UICollectionViewCell {
9 |
10 | @IBOutlet weak var imageView: UIImageView!
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/FlickrService.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 07/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import Alamofire
7 | import SwiftyJSON
8 | import UIKit
9 | import VinceRP
10 |
11 | class FlickrService {
12 |
13 | func searchFlickrForTerm(searchTerm: String) -> Hub<[UIImage]> {
14 |
15 | // Create a UIImage-array stream which represents the result of this search
16 | let result = reactive([UIImage]())
17 |
18 | // Send the search term using the amazing Alamofire framework
19 | Alamofire.request(.GET, searchTerm.flickrSearchURL(), parameters:nil, encoding: .JSON)
20 | .responseData { response in
21 |
22 | // Process the JSON response in a background queue
23 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
24 |
25 | switch response.result {
26 | case .Success(let jsonData):
27 | let json = JSON(data: jsonData)
28 | self.processResult(json, result: result)
29 | case .Failure(let error):
30 |
31 | // Send an error using the extension below
32 | result <- JSON.error(error.localizedDescription)
33 | }
34 | }
35 | }
36 |
37 | // Return with this stream variable as a future
38 | return result
39 | }
40 |
41 | private func processResult(json: JSON, result:Source<[UIImage]>) {
42 | if let error = json.error() {
43 | result <- error
44 | return
45 | }
46 |
47 | let photosContainer = json["photos"]
48 | let photosReceived = photosContainer["photo"].array!
49 | let flickrPhotos = photosReceived.map(UIImage.jsonToImageMap)
50 |
51 | result <- flickrPhotos
52 | }
53 |
54 | }
55 |
56 | extension UIImage {
57 |
58 | static func jsonToImageMap(photoDictionary: JSON) -> UIImage {
59 |
60 | // Parse the metadata for an image
61 | let photoID = photoDictionary["id"].string ?? ""
62 | let farm = photoDictionary["farm"].int ?? 0
63 | let server = photoDictionary["server"].string ?? ""
64 | let secret = photoDictionary["secret"].string ?? ""
65 |
66 | // Build the url of the image
67 | let flickrPhotoURL = NSURL(string: "https://farm\(farm).staticflickr.com/\(server)/\(photoID)_\(secret)_m.jpg")!
68 |
69 | // In a real world application this would be an asnyc call.
70 | let imageData = NSData(contentsOfURL: flickrPhotoURL)
71 | return UIImage(data: imageData!)!
72 | }
73 |
74 | }
75 |
76 | // Helper extension
77 | extension JSON {
78 |
79 | // Is there any error in the JSON answer
80 | func error() -> NSError? {
81 | if let state = self["stat"].string {
82 | switch (state) {
83 | case "ok": return nil
84 | case "fail": return JSON.error(self["message"].string!)
85 | default: return JSON.error("Unknown API error")
86 | }
87 | }
88 | return nil
89 | }
90 |
91 | static func error(reason: String) -> NSError {
92 | return NSError(domain: "FlickrSearch", code: 0, userInfo: [NSLocalizedFailureReasonErrorKey:reason])
93 | }
94 |
95 | }
96 |
97 | extension String {
98 |
99 | // Build the full search URL with tokens and everything
100 | func flickrSearchURL() -> NSURL {
101 |
102 | // URL escape the search term
103 | let escapedTerm = self.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
104 |
105 | // This is the full search URL with api key and paging
106 | let URLString = "https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=74c678b0fd9ff0887a104875925021bf&text=\(escapedTerm)&per_page=20&format=json&nojsoncallback=1"
107 |
108 | return NSURL(string: URLString)!
109 | }
110 |
111 | }
112 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/FlickrViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 05/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import UIKit
7 | import VinceRP
8 |
9 | class FlickrViewControler: UIViewController {
10 |
11 | // Renders the thumbnail images
12 | @IBOutlet weak var collectionView: UICollectionView!
13 |
14 | // Show it till the response arrives
15 | @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
16 |
17 | @IBOutlet weak var searchBar: UISearchBar!
18 |
19 | // If there is no result show this
20 | @IBOutlet weak var noResultsLabel: UILabel!
21 |
22 | // Shows how much time we have left before throttle "timeouts"
23 | @IBOutlet weak var progressView: UIProgressView!
24 |
25 | // Counts how much time we have left before throttle "timeouts"
26 | private var throttleTimeout:Source = reactive(0.0)
27 |
28 | // This reactive variable serves as a future/promise:
29 | // - in the one hand we will "write" image arrays into it
30 | // - in the other hand we observing the changes and react on them
31 | private let searchResults = reactive([UIImage]())
32 |
33 | override func viewDidLoad() {
34 |
35 | // If the results variable changes let's refresh the tableview
36 | // It acts like a future here
37 | self.searchResults.onChange { _ in
38 | self.collectionView.reloadData()
39 | }.dispatchOnMainQueue()
40 |
41 | // True if there is an ongoing search
42 | let searchIsOngoing = reactive(false)
43 |
44 | // True if there is any search results
45 | let hasResult = self.searchResults.map{ $0 != [] }
46 |
47 | let searchTerm = self.searchBar.reactiveText.dispatchOnMainQueue()
48 |
49 | // Hide activity indicator if we are not in a search
50 | self.activityIndicator.reactiveHidden = searchIsOngoing.not()
51 |
52 | // Hide the collection view during the search
53 | self.collectionView.reactiveHidden = searchIsOngoing
54 |
55 | // Update the label on new search
56 | self.noResultsLabel.reactiveText = searchTerm.map {
57 | "Search for '\($0)'"
58 | }
59 |
60 | // Update the progress on every tick of the timer
61 | throttleTimeout.onChange {
62 | self.progressView.setProgress(fminf($0, 1.0), animated: ($0 != 0.0))
63 | }.dispatchOnMainQueue()
64 |
65 | // If we type let's reset the timeout variable and thus the progress
66 | searchTerm.onChange { _ in
67 | self.throttleTimeout <- 0.0
68 | }
69 |
70 | // If there is search result or search is happening let's hide this label
71 | self.noResultsLabel.reactiveHidden = definedAs {
72 | hasResult* || searchIsOngoing*
73 | }
74 |
75 | // If there is no result update the noResultLabel
76 | hasResult.not().onChange { _ in
77 | self.noResultsLabel.text = "No results for '\(self.searchBar.reactiveText*)'"
78 | }.dispatchOnMainQueue()
79 |
80 | // If no update (new keyboard press) within a 1 second time frame
81 | // and there is anything in the searchbar let's propagate the change
82 | searchTerm.throttle(1.0).ignore("").onChange { searchText in
83 |
84 | // Start the search -> it hides the collectionView (line 52) and shows the activity indicator (line 49)
85 | searchIsOngoing <- true
86 |
87 | // Let's start the search and get back the results on the main thread
88 | let searchResult = FlickrService().searchFlickrForTerm(searchText).dispatchOnMainQueue()
89 |
90 | searchResult.onChange { images in
91 |
92 | // Hide the activity indicator and show the collection view
93 | searchIsOngoing <- false
94 |
95 | // Trigger a reload on the collectionview
96 | // It acts like a promise here
97 | self.searchResults <- images
98 | }
99 |
100 | searchResult.onError {
101 |
102 | // Hide the activity indicator and show the collection view
103 | searchIsOngoing <- false
104 |
105 | // Show the error
106 | self.showError($0)
107 | }
108 | }
109 |
110 | // Set the default states
111 | self.activityIndicator.hidden = true
112 | self.noResultsLabel.hidden = true
113 |
114 | // Start the timer
115 | timer(0.1) {
116 |
117 | // Increment the on every tick
118 | // Note: this is an operator overloading (CMD + click on the "+=" to check it out)
119 | self.throttleTimeout += 0.1
120 | }
121 |
122 | }
123 |
124 | // Build and show an alert dialog
125 | private func showError(error: NSError) {
126 |
127 | let alertController = UIAlertController(title: "Flickr error",
128 | message: error.localizedDescription,
129 | preferredStyle: UIAlertControllerStyle.Alert)
130 |
131 | alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Default, handler: nil))
132 |
133 | self.presentViewController(alertController, animated: true, completion: nil)
134 | }
135 | }
136 |
137 | // Make this controller as a datasource of the CollectionView
138 | extension FlickrViewControler: UICollectionViewDataSource {
139 |
140 | func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
141 | return searchResults*.count
142 | }
143 |
144 | func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
145 | let cell = collectionView.dequeueReusableCellWithReuseIdentifier("FlickrCell", forIndexPath: indexPath) as! FlickrPhotoCell
146 | let flickrPhoto = searchResults.value()[indexPath.row]
147 | cell.imageView.image = flickrPhoto
148 | return cell
149 | }
150 |
151 | }
152 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/LoginService.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 13/10/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import Alamofire
7 | import SwiftyJSON
8 | import VinceRP
9 |
10 | // This example service uses a simple login/password service:
11 | // http://todolist.parseapp.com/
12 |
13 | class LoginService {
14 |
15 | func login(username: String, password: String) -> Hub {
16 |
17 | // Let's define a stream of bool values which represents the result of the login
18 | // We'll return this variable as a promise at the end of this method
19 | let returnValue = reactive(false)
20 |
21 | // The necessary parameters for the login, username / password are the dynamic ones
22 | let params = [
23 | "_ApplicationId": "0Oq3tTp9JMvd72LOrGN25PiEq9XgVHCxo57MQbpT",
24 | "_ClientVersion": "js1.1.15",
25 | "_InstallationId": "33bf814e-f1c0-8412-ee3e-76f976898599",
26 | "_JavaScriptKey": "vUFy2o7nFx3eeKVlZneYMPI2MBoxT5LhWNoIWPja",
27 | "_method": "GET",
28 | "username": username,
29 | "password": password,
30 | ]
31 |
32 | // Send the request
33 | Alamofire.request(.POST, "https://api.parse.com/1/login", parameters:params, encoding: .JSON)
34 | .responseData { response in
35 |
36 | // Parse the response
37 | switch response.result {
38 | case .Success(let jsonData):
39 | let json = JSON(data: jsonData)
40 |
41 | // If there is an error field...
42 | if let _ = json["error"].string {
43 |
44 | // ... we send a false here
45 | returnValue <- false
46 | } else {
47 |
48 | // ... we send a true otherwise
49 | returnValue <- true
50 | }
51 |
52 | // If it fails...
53 | case .Failure(let error):
54 | // ... we send an error
55 | returnValue <- self.error("\(error)")
56 | }
57 | }
58 |
59 | // We return with our "future like" reactive variable
60 | return returnValue
61 | }
62 |
63 | private func error(errorString: String) -> NSError {
64 |
65 | return NSError(domain: "VinceRP", code: -1, userInfo: [NSLocalizedFailureReasonErrorKey: errorString])
66 |
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/LoginViewControler.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 05/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import Alamofire
7 | import UIKit
8 | import VinceRP
9 |
10 | private let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
11 |
12 | // Let's add a handy extension helps us to validate the email and password field
13 | extension UITextField {
14 |
15 | var isValidEmail: Bool {
16 | return definedAs {
17 | // Remember * is just a shortcut for getting the current value
18 | let range = self.reactiveText*.rangeOfString(emailRegEx, options:.RegularExpressionSearch)
19 | return range != nil
20 | }*
21 | }
22 |
23 | var isValidPassword: Bool {
24 | return definedAs {
25 | self.reactiveText*.trim().length > 0
26 | }*
27 | }
28 |
29 | }
30 |
31 | class LoginViewControler: UIViewController {
32 |
33 | @IBOutlet weak var emailField: UITextField!
34 | @IBOutlet weak var passwordField: UITextField!
35 | @IBOutlet weak var loginButton: UIButton!
36 | @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
37 |
38 | override func viewDidAppear(animated: Bool) {
39 |
40 | // Make this button blue when enabled and gray when disabled
41 | setupLoginButtonUI()
42 |
43 | // Let's defined reactive version of the enabled property
44 | self.loginButton.reactiveEnabled = definedAs {
45 |
46 | // Whenever email or password field receive's a new value (via typing or copy/paste)
47 | // this 'reactiveEnabled' will receive a new boolean value
48 | // which is true if both 'isValidEmail' and 'isValidPassword' emit a true, false otherwise
49 | self.emailField.isValidEmail &&
50 | self.passwordField.isValidPassword
51 | }
52 |
53 | // Default values for username and password
54 | self.emailField.text = "bvic23@gmail.com"
55 | self.passwordField.text = "123456"
56 |
57 | // Hide the spinner login command is not executing
58 | self.activityIndicator.reactiveHidden = self.loginButton.executing.not()
59 |
60 | // Hide the button if login is in progress
61 | self.loginButton.reactiveHidden = self.loginButton.executing
62 |
63 | // Create a stream of string value start with an empty string
64 | let alert = reactive("")
65 |
66 | // Watch the changes of alert variable and skip the first value
67 | alert.onChange(skipInitial: true) {
68 |
69 | // Get the current value from the stream which is the message we should show in the alert dialog
70 | let message = $0
71 |
72 | // Create an alert controller
73 | let alertController = UIAlertController(title: "Login Result",
74 | message: message,
75 | preferredStyle: UIAlertControllerStyle.Alert)
76 |
77 | // Add a close button
78 | alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Default, handler: nil))
79 |
80 | // Show it
81 | self.presentViewController(alertController, animated: true, completion: nil)
82 | }.dispatchOnMainQueue()
83 |
84 | // Add a clickhandler
85 | self.loginButton.clickHandler = definedAs { handler in // Because this block can contain any kind of threading
86 | // this handler is for marking this clickhandler "done".
87 | // Why this is necessary? Because I like the "executing" property of RACCommand and
88 | // the calling of "done" sets "executing" to false.
89 | // If you have any better idea how to do this please send a PR or create an issue
90 |
91 |
92 | // Close the keyboard
93 | self.emailField.resignFirstResponder()
94 | self.passwordField.resignFirstResponder()
95 |
96 | // Create a loginservice
97 | let loginService = LoginService()
98 |
99 | // Initiate the login process
100 | let login = loginService.login(self.emailField.text!, password: self.passwordField.text!)
101 | login.onChange {
102 |
103 | if $0 {
104 | // Send a greeting
105 | alert <- "Welcome!"
106 | } else {
107 | // Send a greeting
108 | alert <- "Login failed, username or password is invalid!"
109 | }
110 |
111 | // Mark this handler done
112 | handler.done()
113 | }
114 | login.onError { error in
115 |
116 | // Send an error
117 | alert <- "Login failed with error: \(error)"
118 | handler.done()
119 | }
120 | }
121 |
122 | }
123 |
124 | func setupLoginButtonUI() {
125 | self.loginButton.setBackgroundImage(UIImage.imageWithColor(UIColor.blueColor()), forState: .Normal)
126 | self.loginButton.setBackgroundImage(UIImage.imageWithColor(UIColor.grayColor()), forState: .Disabled)
127 | self.loginButton.layer.cornerRadius = 3.0
128 | self.loginButton.layer.masksToBounds = true
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/BasicExample/UIImage+FromColor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 14/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | public extension UIImage {
9 |
10 | // Create an image from a given color
11 | public class func imageWithColor(color: UIColor) -> UIImage {
12 | let rect = CGRectMake(0.0, 0.0, 1.0, 1.0)
13 | UIGraphicsBeginImageContext(rect.size)
14 | let context = UIGraphicsGetCurrentContext()
15 |
16 | CGContextSetFillColorWithColor(context, color.CGColor)
17 | CGContextFillRect(context, rect)
18 |
19 | let image = UIGraphicsGetImageFromCurrentImageContext()
20 | UIGraphicsEndImageContext()
21 |
22 | return image
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/Cartfile:
--------------------------------------------------------------------------------
1 | github "Alamofire/Alamofire"
2 | github "SwiftyJSON/SwiftyJSON" "HEAD"
3 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/examples/Cartfile.resolved:
--------------------------------------------------------------------------------
1 | github "Alamofire/Alamofire" "3.1.0"
2 | github "SwiftyJSON/SwiftyJSON" "3b5d0d4e0c19173b1bf0dc823bde25ad870f70c0"
3 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/logoTrimmed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alltheflow/CopyPasta/79460ff452600945de8c7ef1560c948dfe7b6942/Carthage/Checkouts/VinceRP/logoTrimmed.png
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/performance/Cartfile:
--------------------------------------------------------------------------------
1 | github "JensRavens/Interstellar" "master"
2 | github "ReactiveX/RxSwift" "master"
3 | github "SwiftBond/Bond" "master"
4 | github "ReactiveCocoa/ReactiveCocoa" "v4.0.0-alpha.2"
5 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/performance/Cartfile.resolved:
--------------------------------------------------------------------------------
1 | github "SwiftBond/Bond" "41e557292ee940257216a8b862f0b2da5fd44cb0"
2 | github "JensRavens/Interstellar" "5133f2914830cef456d0cfff832a402d04d61ae3"
3 | github "antitypical/Result" "0.6.0-beta.3"
4 | github "ReactiveX/RxSwift" "c909f0f572d84f7b7578c55b7b16d853ebad5f8a"
5 | github "ReactiveCocoa/ReactiveCocoa" "v4.0.0-alpha.2"
6 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/performance/Performance.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/performance/Performance/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Performance
4 | //
5 | // Created by Viktor Belényesi on 30/11/15.
6 | // Copyright © 2015 Viktor Belenyesi. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | @NSApplicationMain
12 | class AppDelegate: NSObject, NSApplicationDelegate {
13 |
14 | @IBOutlet weak var window: NSWindow!
15 |
16 |
17 | func applicationDidFinishLaunching(aNotification: NSNotification) {
18 | // Insert code here to initialize your application
19 | }
20 |
21 | func applicationWillTerminate(aNotification: NSNotification) {
22 | // Insert code here to tear down your application
23 | }
24 |
25 |
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/performance/Performance/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "size" : "16x16",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "size" : "16x16",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "size" : "32x32",
16 | "scale" : "1x"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "size" : "32x32",
21 | "scale" : "2x"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "size" : "128x128",
26 | "scale" : "1x"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "size" : "128x128",
31 | "scale" : "2x"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "size" : "256x256",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "size" : "256x256",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "size" : "512x512",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "size" : "512x512",
51 | "scale" : "2x"
52 | }
53 | ],
54 | "info" : {
55 | "version" : 1,
56 | "author" : "xcode"
57 | }
58 | }
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/performance/Performance/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSMinimumSystemVersion
26 | $(MACOSX_DEPLOYMENT_TARGET)
27 | NSHumanReadableCopyright
28 | Copyright © 2015 Viktor Belenyesi. All rights reserved.
29 | NSMainNibFile
30 | MainMenu
31 | NSPrincipalClass
32 | NSApplication
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/performance/PerformanceTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/scripts/test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -o pipefail && xcodebuild clean build test \
4 | -project VinceRP.xcodeproj \
5 | -scheme VinceRP_mac \
6 | -sdk macosx \
7 | -enableCodeCoverage YES
8 | ONLY_ACTIVE_ARCH=NO \
9 | GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES \
10 | GCC_GENERATE_TEST_COVERAGE_FILES=YES \
11 | CODE_SIGN_IDENTITY="" \
12 | CODE_SIGNING_REQUIRED=NO
13 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/scripts/unstash.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | CARTHAGE_BINARY_DIR="Carthage/Build"
4 | CARTHAGE_ZIP="Carthage.zip"
5 |
6 | rm -rf "${CARTHAGE_BINARY_DIR}"
7 | mkdir -p "${CARTHAGE_BINARY_DIR}"
8 | curl -L https://www.googledrive.com/host/0B--nGoDU083MUGoyenBlajFIOUk > "${CARTHAGE_BINARY_DIR}/${CARTHAGE_ZIP}"
9 | cd "${CARTHAGE_BINARY_DIR}"
10 | unzip "${CARTHAGE_ZIP}"
11 | rm -f "${CARTHAGE_ZIP}"
12 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp.xcodeproj/xcshareddata/xcschemes/VinceRP-Mac.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
65 |
71 |
72 |
73 |
74 |
75 |
76 |
82 |
83 |
89 |
90 |
91 |
92 |
94 |
95 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp.xcodeproj/xcshareddata/xcschemes/vincerp.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
48 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
79 |
80 |
86 |
87 |
88 |
89 |
90 |
91 |
97 |
98 |
104 |
105 |
106 |
107 |
109 |
110 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Api.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 01/05/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | /* Operators */
7 |
8 | postfix operator * {}
9 |
10 | public postfix func *(arg: Hub) -> T {
11 | return arg.value()
12 | }
13 |
14 | infix operator <- { associativity left precedence 160 }
15 |
16 | public func <-(left: Source, right: NSError) -> Source {
17 | left.error(right)
18 | return left
19 | }
20 |
21 | public func <-(left: Source, right: T) -> Source {
22 | left.update(right)
23 | return left
24 | }
25 |
26 | /* API functions */
27 |
28 | public func definedAs(calc: () -> T) -> Dynamic {
29 | return Dynamic(calc: calc)
30 | }
31 |
32 | public func reactive(initValue: T) -> Source {
33 | return Source(initValue: initValue)
34 | }
35 |
36 | public func reactive() -> Source {
37 | return Source()
38 | }
39 |
40 | public func onChangeDo(source: Hub, callback: (T) -> ()) -> ChangeObserver {
41 | return onChangeDo(source, skipInitial: false, callback: callback)
42 | }
43 |
44 | public func onChangeDo(source: Hub, skipInitial: Bool, callback: (T) -> ()) -> ChangeObserver {
45 | return ChangeObserver(source: source, callback: ({
46 | callback(source.value())
47 | }), skipInitial: skipInitial)
48 | }
49 |
50 | public func onErrorDo(source: Hub, callback: (NSError) -> ()) -> ErrorObserver {
51 | return ErrorObserver(source: source, callback: callback)
52 | }
53 |
54 | public func timer(interval: NSTimeInterval, tick: () -> ()) -> Timer {
55 | return Timer.timer(interval, tick: tick)
56 | }
57 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Convenient/Addable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | public protocol Addable {
7 | func +(lhs: Self, rhs: Self) -> Self
8 | }
9 |
10 | extension Double: Addable {}
11 | extension Float: Addable {}
12 |
13 | public func +=(left: Source, right: T) -> Source {
14 | left <- (left* + right)
15 | return left
16 | }
17 |
18 | public func +=(left: Source, right: T) -> Source {
19 | left <- (left* + right)
20 | return left
21 | }
22 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Core/BatchUpdate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 27/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | protocol UpdateProtocol {
7 | func ancestors() -> [NodeTuple]
8 | }
9 |
10 | public struct BatchUpdate {
11 | var updates: [UpdateProtocol]
12 |
13 | init(_ v: Source, withValue t: T) {
14 | self.updates = [Update(v, t)]
15 | }
16 |
17 | init(updates: [UpdateProtocol], u: Update) {
18 | self.updates = updates.arrayByAppending(u)
19 | }
20 |
21 | func and(v: Source, withValue t: T) -> BatchUpdate {
22 | return BatchUpdate(updates: self.updates, u: Update(v, t))
23 | }
24 |
25 | func now() {
26 | Propagator.dispatch {
27 | Propagator.propagate(self.updates.flatMap {
28 | $0.ancestors()
29 | })
30 | }
31 | }
32 |
33 | }
34 |
35 | struct Update: UpdateProtocol {
36 | let v: Source
37 | let t: T
38 |
39 | init(_ v: Source, _ t: T) {
40 | self.v = v
41 | self.t = t
42 | v.updateSilent(t)
43 | }
44 |
45 | func ancestors() -> [NodeTuple] {
46 | return Array(self.v.children).map {
47 | NodeTuple($0, $0)
48 | }
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Core/ChangeObserver.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 13/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | public class ChangeObserver: Node {
7 |
8 | private static var changeObservers = Set()
9 | var dispatchQueue: dispatch_queue_t!
10 |
11 | let source: Node
12 | let callback: () -> ()
13 |
14 | public init(source: Node, callback: () -> (), skipInitial: Bool = false) {
15 | self.source = source
16 | self.callback = callback
17 |
18 | super.init()
19 |
20 | source.linkChild(self)
21 |
22 | if (!skipInitial) {
23 | trigger()
24 | }
25 |
26 | ChangeObserver.changeObservers.insert(self)
27 | }
28 |
29 | override public var parents: Set {
30 | return toSet(source)
31 | }
32 |
33 | override var level: long {
34 | return long.max
35 | }
36 |
37 | override func ping(incoming: Set) -> Set {
38 | if (!parents.intersect(incoming).isEmpty && source.isSuccess()) {
39 | if let q = dispatchQueue {
40 | dispatch_async(q) {
41 | self.callback()
42 | }
43 | } else {
44 | callback()
45 | }
46 | }
47 | return Set()
48 | }
49 |
50 | private func trigger() {
51 | ping(parents)
52 | }
53 |
54 | override public func kill() {
55 | super.kill()
56 | ChangeObserver.changeObservers.remove(self)
57 | }
58 |
59 | }
60 |
61 | extension ChangeObserver: Dispatchable {
62 |
63 | public func dispatchOnQueue(dispatchQueue: dispatch_queue_t?) -> ChangeObserver {
64 | self.dispatchQueue = dispatchQueue
65 | return self
66 | }
67 |
68 | }
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Core/Dynamic.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | let globalDynamic: DynamicVariable<(Node, Array)> = DynamicVariable(nil)
7 |
8 | public class Dynamic: Incrementing {
9 | private let calc: () -> T
10 |
11 | public init(calc: () -> T) {
12 | self.calc = calc
13 | super.init()
14 | }
15 |
16 | override func makeState() -> UpdateState {
17 | let startID = nextID()
18 |
19 | let (newValue, deps): (Try, Array) = globalDynamic.withValue((self, [])) {
20 | let calcResult = self.probe(self.calc)
21 | guard let deps = globalDynamic.value?.1 else {
22 | return (calcResult, [])
23 | }
24 | return (calcResult, deps)
25 | }
26 |
27 | let levels = Set(deps.map {
28 | $0.level
29 | })
30 |
31 | let level = levels.max(0)
32 |
33 | return UpdateState(Set(deps), level, startID, newValue)
34 | }
35 |
36 | func probe(calc: () -> T) ->Try {
37 | var result: Try?
38 | try2 {
39 | ({
40 | result = Try(calc())
41 | },
42 | catch2: { e in
43 | if let ex = e {
44 | if let e = ex.userInfo!["error"] as? NSError {
45 | result = Try(e)
46 | }
47 | }
48 | },
49 | finally: {
50 |
51 | })
52 | }
53 | return result!
54 | }
55 |
56 | override func ping(incoming: Set) -> Set {
57 | guard !parents.intersect(incoming).isEmpty || incoming.contains(self) else {
58 | return Set()
59 | }
60 | return super.ping(incoming)
61 | }
62 |
63 | override public func toTry() -> Try {
64 | return self.state.value
65 | }
66 |
67 | override func isSuccess() -> Bool {
68 | return self.state.value.isSuccess()
69 | }
70 |
71 | override public var parents: Set {
72 | return state.parents
73 | }
74 |
75 | override var level: long {
76 | return state.level
77 | }
78 |
79 | }
80 |
81 |
82 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Core/ErrorObserver.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 27/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import Foundation
7 |
8 | public class ErrorObserver: ChangeObserver {
9 |
10 | private static var errorObservers = Set()
11 | private var errorCallback: (NSError) -> ()
12 |
13 | public init(source: Node, callback: (NSError) -> (), name: String = "") {
14 | self.errorCallback = callback
15 | super.init(source:source, callback:({}), skipInitial:true)
16 | ErrorObserver.errorObservers.insert(self)
17 | }
18 |
19 | override func ping(incoming: Set) -> Set {
20 | if (!parents.intersect(incoming).isEmpty && !source.isSuccess()) {
21 | if let q = dispatchQueue {
22 | dispatch_async(q) {
23 | self.errorCallback(self.source.error())
24 | }
25 | } else {
26 | self.errorCallback(source.error())
27 | }
28 | }
29 | return Set()
30 | }
31 |
32 | override public func kill() {
33 | super.kill()
34 | ErrorObserver.errorObservers.remove(self)
35 | }
36 |
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Core/Hub+operators.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 27/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | public extension Hub where T: BooleanType {
7 |
8 | public func not() -> Hub {
9 | return self.map(!)
10 | }
11 |
12 | }
13 |
14 | public extension Hub where T: Equatable {
15 |
16 | public func ignore(ignorabeValues: T) -> Hub {
17 | return self.filter { $0 != ignorabeValues }
18 | }
19 |
20 | }
21 |
22 |
23 | public extension Hub {
24 |
25 | public func foreach(skipInitial: Bool = false, callback: T -> ()) -> ChangeObserver {
26 | let obs = ChangeObserver(source:self, callback:{callback(self.value())}, skipInitial:skipInitial)
27 | return obs
28 | }
29 |
30 | public func skipErrors() -> Hub {
31 | return filterAll { $0.isSuccess() }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Core/Hub.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 27/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | public class Hub: Node {
7 |
8 | var dispatchQueue: dispatch_queue_t!
9 |
10 | func currentValue() -> T {
11 | switch (toTry()) {
12 | case .Success(let value): return value
13 | case .Failure(let error): NSException(name:"name", reason:"domain", userInfo:["error":error]).raise()
14 | }
15 | fatalError(UNREACHABLE_CODE)
16 | }
17 |
18 | override public func error() -> NSError {
19 | switch (toTry()) {
20 | case .Failure(let error): return error
21 | case .Success(_): fatalError(UNREACHABLE_CODE)
22 | }
23 | fatalError(UNREACHABLE_CODE)
24 | }
25 |
26 | public func value() -> T {
27 | if let (e, d) = globalDynamic.value {
28 | linkChild(e)
29 | globalDynamic.value = (e, d.arrayByPrepending(self))
30 | } else {
31 | globalDynamic.value = nil
32 | }
33 | return currentValue()
34 | }
35 |
36 | func propagate() {
37 | Propagator.dispatch {
38 | let mappedTargets = self.children.map {
39 | NodeTuple(self, $0)
40 | }
41 | Propagator.propagate(mappedTargets)
42 | }
43 | }
44 |
45 | public func toTry() -> Try {
46 | fatalError(ABSTRACT_METHOD)
47 | }
48 |
49 | public func killAll() {
50 | kill()
51 | descendants.forEach {
52 | $0.kill()
53 | }
54 | }
55 |
56 | public func recalc() {
57 | Propagator.propagate(toSet(NodeTuple(self, self)))
58 | }
59 |
60 | public func onChange(skipInitial skipInitial: Bool = true, callback: (T) -> ()) -> ChangeObserver {
61 | return onChangeDo(self, skipInitial: skipInitial) {
62 | callback($0)
63 | }
64 | }
65 |
66 | public func onError(callback: (NSError) -> ()) -> ErrorObserver {
67 | return onErrorDo(self) {
68 | callback($0)
69 | }
70 | }
71 |
72 | }
73 |
74 | extension Hub: Dispatchable {
75 |
76 | public func dispatchOnQueue(dispatchQueue: dispatch_queue_t?) -> Hub {
77 | self.dispatchQueue = dispatchQueue
78 | return self
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Core/Incrementing.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belényesi on 01/12/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | public class Incrementing: Hub {
7 |
8 | private var _state: AtomicReference>
9 |
10 | override init() {
11 | _state = AtomicReference(UpdateState(Try(noValueError)))
12 | super.init()
13 | _state = AtomicReference(self.makeState())
14 | }
15 |
16 | var state: UpdateState {
17 | return _state.value
18 | }
19 |
20 | func toTry() -> UpdateState {
21 | return self.state
22 | }
23 |
24 | func makeState() -> UpdateState {
25 | fatalError(ABSTRACT_METHOD)
26 | }
27 |
28 | override func ping(incoming: Set) -> Set {
29 | let newState = makeState()
30 |
31 | if newState.id <= _state.value.id {
32 | return Set()
33 | }
34 |
35 | if newState.value.description == _state.value.value.description {
36 | return Set()
37 | }
38 |
39 | _state.value = newState
40 | return children
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Core/Mapper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 13/05/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | class Mapper: Wrapper {
7 |
8 | private let transformer: Try -> Try
9 |
10 | init(_ source: Hub, _ transformer: Try -> Try) {
11 | self.transformer = transformer
12 | super.init(source)
13 | }
14 |
15 | override var state: UpdateState {
16 | return makeState()
17 | }
18 |
19 | override func makeState() -> UpdateState {
20 | return UpdateState(nextID(), transformer(source.toTry()))
21 | }
22 |
23 | }
24 |
25 | public extension Hub {
26 |
27 | public func map(f: T -> A) -> Hub {
28 | return Mapper(self) { x in
29 | return x.map(f)
30 | }
31 | }
32 |
33 | public func mapAll(f: Try -> Try) -> Hub {
34 | return Mapper(self, f)
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Core/Node.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 19/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | public class Node: Hashable {
7 |
8 | private static var hashCounter = AtomicLong(0)
9 | private let childrenHolder = AtomicReference>(WeakSet())
10 | public let hashValue = Int(Node.hashCounter.getAndIncrement()) // Hashable
11 |
12 | public var children: Set {
13 | return childrenHolder.value.filter {
14 | $0.parents.contains(self)
15 | }.set
16 | }
17 |
18 | public var descendants: Set {
19 | return children ++ children.flatMap {
20 | $0.descendants
21 | }
22 | }
23 |
24 | public var parents: Set {
25 | return Set()
26 | }
27 |
28 | public var ancestors: Set {
29 | return parents ++ parents.flatMap {
30 | $0.ancestors
31 | }
32 | }
33 |
34 | func isSuccess() -> Bool {
35 | return true
36 | }
37 |
38 | func error() -> NSError {
39 | fatalError(ABSTRACT_METHOD)
40 | }
41 |
42 | func linkChild(child: Node) {
43 | if (!childrenHolder.value.hasElementPassingTest {$0 == child}) {
44 | childrenHolder.value.insert(child)
45 | }
46 | }
47 |
48 | func unlinkChild(child: Node) {
49 | childrenHolder.value = childrenHolder.value.filter {$0 != child}
50 | }
51 |
52 | func ping(incoming: Set) -> Set {
53 | fatalError(ABSTRACT_METHOD)
54 | }
55 |
56 | private var alive = true
57 |
58 | public func kill() {
59 | alive = false
60 | parents.forEach {
61 | $0.unlinkChild(self)
62 | }
63 | }
64 |
65 | var level: long {
66 | return 0
67 | }
68 |
69 | }
70 |
71 | public func ==(lhs: Node, rhs: Node) -> Bool {
72 | return lhs.hashValue == rhs.hashValue
73 | }
74 |
75 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Core/NodeTuple.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 11/3/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | struct NodeTuple: Hashable {
7 | let source: Node
8 | let reactor: Node
9 |
10 | init(_ source: Node, _ reactor: Node) {
11 | self.source = source
12 | self.reactor = reactor
13 | }
14 |
15 | var hashValue: Int {
16 | return source.hashValue ^ reactor.hashValue
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Core/Propagator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | func ==(lhs: NodeTuple, rhs: NodeTuple) -> Bool {
7 | return lhs.source.hashValue == rhs.source.hashValue && lhs.reactor.hashValue == rhs.source.hashValue
8 | }
9 |
10 |
11 | public class Propagator {
12 |
13 | public static var async: Bool = false
14 | public static let propagationQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)
15 |
16 | static func dispatch(block: () -> ()) {
17 | if async {
18 | dispatch_async(propagationQueue) {
19 | block()
20 | }
21 | } else {
22 | block()
23 | }
24 | }
25 |
26 | static func propagate(nodes: [NodeTuple]) {
27 | self.propagate(Set(nodes))
28 | }
29 |
30 | static func propagate(nodes: Set) {
31 | guard nodes.count > 0 else {
32 | return
33 | }
34 |
35 | let minLevel = nodes.map{ $0.reactor.level }.min(0)
36 | let (now, later) = nodes.partition {
37 | $0.reactor.level == minLevel
38 | }
39 |
40 | let next = now.groupBy{
41 | $0.reactor
42 | }.mapValues{
43 | $0.map{ $0.source }
44 | }.map{ (target, pingers) in
45 | return target.ping(pingers).map {
46 | NodeTuple(target, $0)
47 | }
48 | }.flatten()
49 |
50 | propagate(next + later)
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Core/Reducer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 13/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | class Reducer: Wrapper {
7 |
8 | private let transformer: (UpdateState, Try) -> UpdateState
9 |
10 | init(_ source: Hub, _ transformer: (UpdateState, Try) -> UpdateState) {
11 | self.transformer = transformer
12 | super.init(source)
13 | }
14 |
15 | override func makeState() -> UpdateState {
16 | return transformer(self.state, source.toTry())
17 | }
18 |
19 | }
20 |
21 | public extension Hub {
22 |
23 | public func filter(successPred: T -> Bool) -> Hub {
24 | return Reducer(self) { (x, y) in
25 | switch (x, y) {
26 | case (_, .Success(let value)) where successPred(value): return UpdateState(y)
27 | case (_, .Failure(_)): return UpdateState(y)
28 | default: return x
29 | }
30 | }
31 | }
32 |
33 | public func filterAll(predicate: Try -> Bool) -> Hub {
34 | return Reducer(self) { (x, y) in
35 | guard predicate(y) else {
36 | return x
37 | }
38 | return UpdateState(y)
39 | }
40 | }
41 |
42 | public func reduce(combiner: (T, T) -> T) -> Hub {
43 | return Reducer(self) { (x, y) in
44 | switch (x.value, y) {
45 | case (.Success(let a), .Success(let b)): return UpdateState(Try(combiner(a, b)))
46 | default: return UpdateState(y)
47 | }
48 | }
49 | }
50 |
51 | public func reduceAll(combiner: (UpdateState, Try) -> Try) -> Hub {
52 | return Reducer(self) { (x, y) in
53 | UpdateState(combiner(x, y))
54 | }
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Core/Source.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 15/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | let noValueError = NSError(domain: "no value", code: -1, userInfo: nil)
7 |
8 | public class Source: Hub {
9 |
10 | let state: AtomicReference>
11 |
12 | public init(initValue: T) {
13 | state = AtomicReference(Try(initValue))
14 | super.init()
15 | }
16 |
17 | public override init() {
18 | state = AtomicReference(Try(noValueError))
19 | super.init()
20 | }
21 |
22 | public func update(newValue: T) {
23 | self.updateSilent(newValue)
24 | self.propagate()
25 | }
26 |
27 | public func error(error: NSError) {
28 | self.state.value = Try(error)
29 | self.propagate()
30 | }
31 |
32 | public func updateSilent(newValue:T) {
33 | self.state.value = Try(newValue)
34 | }
35 |
36 | override func isSuccess() -> Bool {
37 | return toTry().isSuccess()
38 | }
39 |
40 | override public func toTry() -> Try {
41 | return state.value
42 | }
43 |
44 | override func ping(incoming: Set) -> Set {
45 | return children
46 | }
47 |
48 | public func hasValue() -> Bool {
49 | if !isSuccess() {
50 | switch toTry() {
51 | case .Success(_): return true
52 | case .Failure(let e): return e !== noValueError
53 | }
54 | }
55 | return true
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Core/Throttle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 16/10/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | class Throttle: Dynamic {
7 |
8 | private let interval: NSTimeInterval
9 | private let debounceLevel: long
10 | private var timer: NSTimer?
11 | private var incoming: Set?
12 |
13 | init(source: Hub, interval: NSTimeInterval) {
14 | self.interval = interval
15 | self.debounceLevel = source.level + 1
16 | super.init {
17 | source.value()
18 | }
19 | }
20 |
21 | func callSelectorAsync(selector: Selector, object: AnyObject?, delay: NSTimeInterval) -> NSTimer {
22 | return NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: selector, userInfo: object, repeats: false)
23 | }
24 |
25 | @objc func pingAsync() {
26 | if let i = self.incoming {
27 | if super.ping(i).count > 0 {
28 | self.propagate()
29 | }
30 | }
31 | }
32 |
33 | override func ping(incoming: Set) -> Set {
34 | self.incoming = incoming
35 | if let t = self.timer {
36 | t.invalidate()
37 | self.timer = nil
38 | }
39 | self.timer = callSelectorAsync(Selector("pingAsync"), object:nil, delay: self.interval)
40 | return Set()
41 | }
42 |
43 | override var level: long {
44 | return self.debounceLevel
45 | }
46 | }
47 |
48 | public extension Hub {
49 |
50 | public func throttle(interval: NSTimeInterval) -> Hub {
51 | return Throttle(source: self, interval: interval)
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Core/Wrapper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 27/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | class Wrapper: Incrementing {
7 |
8 | let source: Hub
9 |
10 | init(_ source: Hub) {
11 | self.source = source
12 | super.init()
13 | source.linkChild(self)
14 | }
15 |
16 | override var level: long {
17 | return self.source.level + 1
18 | }
19 |
20 | override var parents: Set {
21 | return toSet(source)
22 | }
23 |
24 | override func toTry() -> Try {
25 | return self.state.value
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Threading/AtomicLong.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | public typealias long = Int32
7 |
8 | public class AtomicLong: Hashable {
9 |
10 | private let lock = Spinlock()
11 |
12 | private var _value: long
13 |
14 | var value: long {
15 |
16 | get {
17 | return self.lock.around {
18 | self._value
19 | }
20 | }
21 |
22 | set(value) {
23 | self.lock.around {
24 | self._value = value
25 | }
26 | }
27 | }
28 |
29 | public init(_ value: long) {
30 | _value = value
31 | }
32 |
33 | public func getAndIncrement() -> long {
34 | let current = value
35 | self.value = current + 1
36 | return current
37 | }
38 |
39 |
40 | public var hashValue: Int {
41 | return value.hashValue
42 | }
43 |
44 | }
45 |
46 | public func ==(lhs: AtomicLong, rhs: AtomicLong) -> Bool {
47 | return lhs.value == rhs.value
48 | }
49 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Threading/AtomicReference.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | class AtomicReference {
7 |
8 | private let lock = Spinlock()
9 |
10 | private var _value: T
11 |
12 | var value: T {
13 |
14 | get {
15 | return self.lock.around {
16 | self._value
17 | }
18 | }
19 |
20 | set(value) {
21 | self.lock.around {
22 | self._value = value
23 | }
24 | }
25 | }
26 |
27 | init(_ value: T) {
28 | _value = value
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Threading/Dispatchable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 27/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | // TODO: add tests
7 | public protocol Dispatchable {
8 | typealias D
9 |
10 | func dispatchOnQueue(dispatchQueue: dispatch_queue_t?) -> D
11 | func dispatchOnMainQueue() -> D
12 | func dispatchOnCurrentQueue() -> D
13 | func dispatchOnBackgroundQueue() -> D
14 |
15 | }
16 |
17 | public extension Dispatchable {
18 |
19 | public func dispatchOnMainQueue() -> D {
20 | return self.dispatchOnQueue(dispatch_get_main_queue()!)
21 | }
22 |
23 | public func dispatchOnCurrentQueue() -> D {
24 | return self.dispatchOnQueue(nil)
25 | }
26 |
27 | public func dispatchOnBackgroundQueue() -> D {
28 | return self.dispatchOnQueue(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)!)
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Threading/DynamicVariable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 | // Inspired by
6 | // http://www.scala-lang.org/api/2.11.5/index.html#scala.util.DynamicVariable
7 | // and
8 | // https://searchcode.com/codesearch/view/18473763/
9 | // and
10 | // http://scalageek.blogspot.hu/2013/02/when-to-use-dynamic-variables.html?m=1
11 |
12 | public class DynamicVariable {
13 |
14 | private let threadLocal: ThreadLocal
15 |
16 | public var value: T? {
17 | set {
18 | threadLocal.value = newValue
19 | }
20 | get {
21 | return threadLocal.value
22 | }
23 | }
24 |
25 | public init(_ value: T?) {
26 | self.threadLocal = ThreadLocal(value: value, key: "DynamicVariable")
27 | }
28 |
29 | public func withValue(newval: T, @noescape _ thunk: () -> S) -> S {
30 | let oldval = value
31 |
32 | // set the context
33 | self.value = newval
34 |
35 | let result = thunk()
36 |
37 | // restore the context
38 | self.value = oldval
39 |
40 | return result
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Threading/Spinlock.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 11/30/15.
3 | // Copyright © 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | class Spinlock {
7 | private var lock: OSSpinLock = OS_SPINLOCK_INIT
8 |
9 | func around(code: Void -> Void) {
10 | OSSpinLockLock(&lock)
11 | code()
12 | OSSpinLockUnlock(&lock)
13 | }
14 |
15 | func around(code: Void -> T) -> T {
16 | OSSpinLockLock(&lock)
17 | let result = code()
18 | OSSpinLockUnlock(&lock)
19 |
20 | return result
21 | }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Threading/ThreadLocal.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | final class Box {
7 |
8 | var value: T
9 |
10 | init(_ value: T) {
11 | self.value = value
12 | }
13 |
14 | }
15 |
16 | public class ThreadLocal {
17 |
18 | private let key: NSString
19 |
20 | public init(value: T?, key: NSString) {
21 | self.key = key
22 | self.value = value
23 | }
24 |
25 | public var value: T? {
26 | set {
27 | if let v = newValue {
28 | NSThread.currentThread().threadDictionary[key] = Box(v)
29 | } else {
30 | // TODO: add test
31 | NSThread.currentThread().threadDictionary.removeObjectForKey(key)
32 | }
33 | }
34 | get {
35 | guard let r: Box = NSThread.currentThread().threadDictionary[key] as? Box else {
36 | return nil
37 | }
38 | return r.value
39 | }
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Timer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 10/18/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | public class Timer {
7 |
8 | private var timer: NSTimer?
9 | private var tick: (() -> ())?
10 |
11 | private init() {}
12 |
13 | @objc private func timerHandler() {
14 | self.tick!()
15 | }
16 |
17 | public func cancel() {
18 | guard let t = self.timer else {
19 | return
20 | }
21 | t.invalidate()
22 | self.timer = nil
23 | }
24 |
25 | class func timer(interval: NSTimeInterval, tick: () ->()) -> Timer {
26 | let result = Timer()
27 | let t = NSTimer.scheduledTimerWithTimeInterval(interval, target: result, selector: Selector("timerHandler"), userInfo: nil, repeats: true)
28 | result.tick = tick
29 | result.timer = t
30 | return result
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Util/CommonConstants.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | let ABSTRACT_METHOD = "Abstract method: override me"
7 | let UNREACHABLE_CODE = "Unreachable code: you should not see this"
8 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Util/ExceptionHandling.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/06/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | func try2(maker: ()->(()->(), catch2:((NSException!)->())?, finally:(()->())? )) {
7 | let (action, catch2, finally) = maker()
8 | VRPNSObjectHelper.try2InvokeBlock(action, catch2: catch2, finally: finally)
9 | }
10 |
11 | func try2(maker: ()->( ()->T, catch2:((NSException!)->())?, finally: (()->())? )) -> T? {
12 | let (action, catch2, finally) = maker()
13 | let result : AnyObject! = VRPNSObjectHelper.try2InvokeBlockWithReturn(action, catch2: { ex in
14 | if let catch2Clause = catch2 {
15 | catch2Clause(ex)
16 | }
17 | return nil
18 | }, finally: finally)
19 | if (result != nil) {
20 | return result as? T
21 | } else {
22 | return nil
23 | }
24 | }
25 |
26 | func try2(maker: ()->( ()->T, catch2:((NSException!)->T)?, finally: (()->())? )) -> T? {
27 | let (action, catch2, finally) = maker()
28 | let result : AnyObject! = VRPNSObjectHelper.try2InvokeBlockWithReturn(action, catch2: catch2, finally: finally)
29 | if (result != nil) {
30 | return result as? T
31 | } else {
32 | return nil
33 | }
34 | }
35 |
36 | func throw2(name:String, message:String) {
37 | VRPNSObjectHelper.throwExceptionNamed(name, message: message)
38 | }
39 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Util/Flattenable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Flattenable.swift
3 | // VinceRP
4 | //
5 | // Created by Viktor Belényesi on 11/3/15.
6 | // Copyright © 2015 Viktor Belenyesi. All rights reserved.
7 | //
8 |
9 | public protocol Flattenable {
10 | func flatten() -> Self
11 | }
12 |
13 | extension Flattenable where Self: SequenceType {
14 |
15 | public func flatten() -> Self {
16 | return self
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Util/FunctionalArray.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | extension Array {
7 |
8 | public func arrayByPrepending(elem: Element) -> Array {
9 | var mutableCopy = self
10 | mutableCopy.insert(elem, atIndex: 0)
11 | let result = mutableCopy
12 | return result
13 | }
14 |
15 | public func arrayByAppending(elem: Element) -> Array {
16 | var mutableCopy = self
17 | mutableCopy.append(elem)
18 | let result = mutableCopy
19 | return result
20 | }
21 |
22 | }
23 |
24 | extension Array where Element: SequenceType {
25 |
26 | public func flatten() -> [Element.Generator.Element] {
27 | return self.flatMap{$0}
28 | }
29 |
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Util/FunctionalDictionary.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 21/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | extension Dictionary {
7 |
8 | init(_ seq: S) {
9 | self.init()
10 | for (k, v) in seq {
11 | self[k] = v
12 | }
13 | }
14 |
15 | public func mapValues(transform: Value -> S) -> Dictionary {
16 | return Dictionary(zip(self.keys, self.values.map(transform)))
17 | }
18 |
19 | public func map(transform: (Key, Value) -> S) -> [S] {
20 | var results = [S]()
21 | for k in self.keys {
22 | guard let v = self[k] else {
23 | continue
24 | }
25 | results.append(transform(k, v))
26 | }
27 | return results
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Util/FunctionalSet.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 21/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | public func toSet(e: T...) -> Set {
7 | return Set(e)
8 | }
9 |
10 | extension Set {
11 |
12 | public func partition(@noescape filterFunc: (Generator.Element) -> Bool) -> (Set, Set) {
13 | let result1 = self.filter(filterFunc)
14 | let result2 = self.filter{!filterFunc($0)}
15 | return (Set(result1), Set(result2))
16 | }
17 |
18 | public func groupBy(@noescape filterFunc: (Generator.Element) -> U) -> [U : Set] {
19 | var result = [U: Set]()
20 | for i in self {
21 | let u = filterFunc(i)
22 | guard let bag = result[u] else {
23 | result[u] = toSet(i)
24 | continue
25 | }
26 | result[u] = bag ++ toSet(i)
27 | }
28 | return result
29 | }
30 |
31 | }
32 |
33 | extension SequenceType where Generator.Element: Hashable {
34 |
35 | public func hasElementPassingTest(@noescape filterFunc: (Self.Generator.Element) -> Bool) -> Bool {
36 | let result = self.filter(filterFunc)
37 | return result.count > 0
38 | }
39 |
40 | }
41 |
42 | extension SequenceType where Generator.Element: Comparable {
43 |
44 | public func min(fallbackValue: Self.Generator.Element) -> Self.Generator.Element {
45 | guard let result = self.minElement() else {
46 | return fallbackValue
47 | }
48 | return result
49 | }
50 |
51 | public func max(fallbackValue: Self.Generator.Element) -> Self.Generator.Element {
52 | guard let result = self.maxElement() else {
53 | return fallbackValue
54 | }
55 | return result
56 | }
57 | }
58 |
59 | extension Set: Flattenable {
60 |
61 | public func filter(@noescape includeElement: (Element) -> Bool) -> Set {
62 | let arr = Array(self)
63 | let result = arr.filter(includeElement)
64 | return Set(result)
65 | }
66 |
67 | public func map(@noescape transform: (Element) -> U) -> Set {
68 | let arr = Array(self)
69 | let result = arr.map(transform)
70 | return Set(result)
71 | }
72 |
73 | public func flatMap(transform: (Element) -> U) -> Set {
74 | let arr = Array(self)
75 | let result = arr.flatMap(transform)
76 | return Set(result)
77 | }
78 |
79 | public func flatMap(@noescape transform: (Element) -> T?) -> Set {
80 | let arr = Array(self)
81 | let result = arr.flatMap(transform)
82 | return Set(result)
83 | }
84 |
85 | }
86 |
87 | extension Set where Element:SequenceType, Element.Generator.Element: Hashable {
88 |
89 | public func flatten() -> Set {
90 | return self.flatMap{$0}
91 | }
92 |
93 | }
94 |
95 | infix operator ++ { associativity left precedence 160 }
96 | public func ++(left: Set, right: Set) -> Set {
97 | return left.union(right)
98 | }
99 |
100 | public func ++(left: Set, right: T) -> Set {
101 | return left ++ toSet(right)
102 | }
103 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Util/ReactivePropertyGenerator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 25/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | public class ReactivePropertyGenerator {
7 |
8 | // TODO: unittest -> check for memory leaks
9 | private static var propertyMap = [String: Node]()
10 | private static var observerMap = [String: PropertyObserver]()
11 |
12 | init() {}
13 |
14 | static func getKey(targetObject: AnyObject, propertyName: String) -> String {
15 | return "\(targetObject.hash)\(propertyName) "
16 | }
17 |
18 | static func getEmitter(targetObject: AnyObject, propertyName: String) -> Source? {
19 | let key = getKey(targetObject, propertyName: propertyName)
20 | return propertyMap[key] as! Source?
21 | }
22 |
23 | static func synthesizeEmitter(initValue: T) -> Source {
24 | return Source(initValue: initValue)
25 | }
26 |
27 | static func synthesizeObserver(targetObject: AnyObject, propertyName: String, initValue: T) -> PropertyObserver {
28 | return PropertyObserver(targetObject: targetObject as! NSObject, propertyName: propertyName) { (currentTargetObject: NSObject, currentPropertyName:String, currentValue:AnyObject) in
29 | if let existingEmitter:Source = getEmitter(currentTargetObject, propertyName: propertyName) {
30 | existingEmitter.update(currentValue as! T)
31 | }
32 | }
33 | }
34 |
35 | static func createEmitter(targetObject: AnyObject, propertyName: String, initValue: T) -> Source {
36 | let result = synthesizeEmitter(initValue)
37 | let key = getKey(targetObject, propertyName: propertyName)
38 | propertyMap[key] = result
39 | return result
40 | }
41 |
42 | static func createObserver(targetObject: AnyObject, propertyName: String, initValue: T) -> PropertyObserver {
43 | let result = synthesizeObserver(targetObject, propertyName: propertyName, initValue: initValue)
44 | let key = getKey(targetObject, propertyName: propertyName)
45 | observerMap[key] = result
46 | return result
47 | }
48 |
49 | public static func source(targetObject: AnyObject, propertyName: String, initValue: T, initializer: ((Source) -> ())? = nil) -> Source {
50 | if let emitter:Source = getEmitter(targetObject, propertyName: propertyName) {
51 | return emitter
52 | }
53 |
54 | let emitter = createEmitter(targetObject, propertyName: propertyName, initValue: initValue)
55 | if let i = initializer {
56 | i(emitter)
57 | }
58 | return emitter
59 | }
60 |
61 | public static func property(targetObject: AnyObject, propertyName: String, initValue: T, initializer: ((Source) -> ())? = nil) -> Hub {
62 | let result = source(targetObject, propertyName: propertyName, initValue: initValue, initializer: initializer)
63 | createObserver(targetObject, propertyName: propertyName, initValue: initValue)
64 | return result as Hub
65 | }
66 | }
67 |
68 | private var propertyObserverContext = 0
69 |
70 | class PropertyObserver: NSObject {
71 | let targetObject: NSObject
72 | let propertyName: String
73 | let propertyChangeHandler: (NSObject, String, AnyObject) -> Void
74 |
75 | init(targetObject:NSObject, propertyName: String, propertyChangeHandler: (NSObject, String, AnyObject) -> Void) {
76 | self.targetObject = targetObject
77 | self.propertyName = propertyName
78 | self.propertyChangeHandler = propertyChangeHandler
79 | super.init()
80 | self.targetObject.addObserver(self, forKeyPath: propertyName, options: .New, context: &propertyObserverContext)
81 | }
82 |
83 | override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer) {
84 | if context == &propertyObserverContext {
85 | if self.propertyName == keyPath {
86 | if let newValue = change?[NSKeyValueChangeNewKey] {
87 | self.propertyChangeHandler(self.targetObject, self.propertyName, newValue)
88 | }
89 | }
90 | } else {
91 | super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
92 | }
93 | }
94 |
95 | deinit {
96 | self.targetObject.removeObserver(self, forKeyPath: propertyName, context: &propertyObserverContext)
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Util/Try.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 20/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 | // https://github.com/scala/scala/blob/2.11.x/src/library/scala/util/Try.scala
6 |
7 | public enum Try: CustomStringConvertible {
8 |
9 | case Success(T)
10 | case Failure(NSError)
11 |
12 | public init(_ error: NSError) {
13 | self = .Failure(error)
14 | }
15 |
16 | public init(_ value: T) {
17 | self = .Success(value)
18 | }
19 |
20 | public func isSuccess() -> Bool {
21 | switch self {
22 | case .Success:
23 | return true
24 | case .Failure:
25 | return false
26 | }
27 | }
28 |
29 | public func isFailure() -> Bool {
30 | return !isSuccess()
31 | }
32 |
33 | public func map(transformFunc: T -> U) -> Try {
34 | switch self {
35 | case .Success(let value):
36 | return .Success(transformFunc(value))
37 | case .Failure(let error):
38 | return .Failure(error)
39 | }
40 | }
41 |
42 | public var description : String {
43 | switch self {
44 | case .Success(let value): return "\(value)"
45 | case .Failure(let error): return "\(error)"
46 | }
47 | }
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Util/VRPNSObjectHelper.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/06/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | #import
7 |
8 | @interface VRPNSObjectHelper : NSObject
9 | + (void)try2InvokeBlock:(void(^)(void))try2Block catch2:(void(^)(NSException*))catch2Block finally:(void(^)(void))finallyBlock;
10 | + (id)try2InvokeBlockWithReturn:(id(^)(void))try2Block catch2:(id(^)(NSException*))catch2Block finally:(void(^)(void))finallyBlock;
11 | + (void)throwExceptionNamed:(NSString *)name message:(NSString *)message;
12 | @end
13 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Util/VRPNSObjectHelper.m:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/06/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | #import "VRPNSObjectHelper.h"
7 |
8 | #import
9 |
10 | @implementation VRPNSObjectHelper
11 |
12 | + (void)try2InvokeBlock:(void(^)(void))try2Block catch2:(void(^)(NSException*))catch2Block finally:(void(^)(void))finallyBlock {
13 | NSAssert(try2Block != NULL, @"try2 block cannot be null");
14 | NSAssert(catch2Block != NULL || finallyBlock != NULL, @"catch2 or finally block must be provided");
15 | @try {
16 | try2Block();
17 | }
18 | @catch (NSException *ex) {
19 | if(catch2Block != NULL) {
20 | catch2Block(ex);
21 | }
22 | }
23 | @finally {
24 | if(finallyBlock != NULL) {
25 | finallyBlock();
26 | }
27 | }
28 | }
29 |
30 | + (id)try2InvokeBlockWithReturn:(id(^)(void))try2Block catch2:(id(^)(NSException*))catch2Block finally:(void(^)(void))finallyBlock {
31 | NSAssert(try2Block != NULL, @"try2 block cannot be null");
32 | NSAssert(catch2Block != NULL || finallyBlock != NULL, @"catch2 or finally block must be provided");
33 |
34 | id returnValue = nil;
35 | @try {
36 | returnValue = try2Block();
37 | }
38 | @catch (NSException *ex) {
39 | if(catch2Block != NULL) {
40 | returnValue = catch2Block(ex);
41 | }
42 | }
43 | @finally {
44 | if(finallyBlock != NULL) {
45 | finallyBlock();
46 | }
47 | }
48 | return returnValue;
49 | }
50 |
51 | + (void)throwExceptionNamed:(NSString *)name message:(NSString *)message {
52 | [NSException raise:name format:@"message:%@", message];
53 | }
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Util/WeakReference.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 21/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 | // https://github.com/scala/scala/blob/2.11.x/src/library/scala/ref/WeakReference.scala
6 |
7 | public class WeakReference: Hashable {
8 | public weak var value: T?
9 |
10 | public init(_ value: T) {
11 | self.value = value
12 | }
13 |
14 | public var hashValue: Int {
15 | guard let v = self.value else {
16 | return 0
17 | }
18 | return v.hashValue
19 | }
20 | }
21 |
22 | public func ==(lhs: WeakReference, rhs: WeakReference) -> Bool {
23 | return lhs.hashValue == rhs.hashValue
24 | }
25 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Common/Util/WeakSet.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | public class WeakSet {
7 | private var _array: [WeakReference]
8 |
9 | public init() {
10 | _array = Array()
11 | }
12 |
13 | public init(_ array: [T]) {
14 | _array = array.map {
15 | WeakReference($0)
16 | }
17 | }
18 |
19 | public var set: Set {
20 | return Set(self.array())
21 | }
22 |
23 | public func insert(member: T) {
24 | for e in _array {
25 | if e.hashValue == member.hashValue {
26 | return
27 | }
28 | }
29 | _array.append(WeakReference(member))
30 | }
31 |
32 | public func filter(@noescape includeElement: (T) -> Bool) -> WeakSet {
33 | return WeakSet(self.array().filter(includeElement))
34 | }
35 |
36 | public func hasElementPassingTest(@noescape filterFunc: (T) -> Bool) -> Bool {
37 | return self.array().hasElementPassingTest(filterFunc)
38 | }
39 |
40 | public func map(@noescape transform: (T) -> U) -> WeakSet {
41 | return WeakSet(self.array().map(transform))
42 | }
43 |
44 | public func flatMap(@noescape transform: (T) -> U?) -> WeakSet {
45 | return WeakSet(self.array().flatMap(transform))
46 | }
47 |
48 | private func array() -> Array {
49 | var result = Array()
50 | for item in _array {
51 | if let v = item.value {
52 | result.append(v)
53 | }
54 | }
55 | return result
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/AppKit/NSResponder+VinceRP.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Agnes Vasarhelyi on 04/11/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import AppKit
7 |
8 | public extension NSResponder {
9 |
10 | public func reactiveProperty(forProperty propertyName: String, initValue: T, initializer: ((Source) -> ())? = nil) -> Hub {
11 | return ReactivePropertyGenerator.property(self, propertyName: propertyName, initValue: initValue, initializer: initializer)
12 | }
13 |
14 | public func reactiveEmitter(name propertyName: String, initValue: T) -> Source {
15 | return ReactivePropertyGenerator.source(self, propertyName: propertyName, initValue: initValue)
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/AppKit/NSTextField+VinceRP.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Agnes Vasarhelyi on 17/11/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import AppKit
7 |
8 | extension NSTextField {
9 |
10 | public var reactiveText: Hub {
11 | get {
12 | return reactiveProperty(forProperty: "text", initValue: self.stringValue) { emitter in
13 | self.addChangeHandler() { textField in
14 | emitter <- textField.stringValue
15 | }
16 | }
17 | }
18 |
19 | set {
20 | newValue.onChange {
21 | self.stringValue = $0
22 | }.dispatchOnMainQueue()
23 | }
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/AppKit/NSTextField+didChange.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Agnes Vasarhelyi on 17/11/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import AppKit
7 |
8 | private typealias EventHandler = (NSTextField) -> ()
9 | private var eventHandlers = [NSTextField: [EventHandler]]()
10 |
11 | extension NSTextField {
12 |
13 | public func addChangeHandler(actionBlock: (NSTextField) -> ()) {
14 | if let handlers = eventHandlers[self] {
15 | eventHandlers[self] = handlers.arrayByAppending(actionBlock)
16 | } else {
17 | eventHandlers[self] = [actionBlock]
18 | }
19 |
20 | self.action = Selector("eventHandler:")
21 | self.target = self
22 | }
23 |
24 | // TODO: add removeChangeHandler
25 | public func eventHandler(sender: NSTextField) {
26 | if let handlers = eventHandlers[sender] {
27 | for handler in handlers {
28 | handler(sender)
29 | }
30 | }
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/AppKit/NSView+VinceRP.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Agnes Vasarhelyi on 17/11/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import AppKit
7 |
8 | public extension NSView {
9 |
10 | public var reactiveHidden: Hub {
11 | get {
12 | return reactiveProperty(forProperty: "hidden", initValue: true)
13 | }
14 |
15 | set {
16 | newValue.onChange {
17 | self.hidden = self.mapReactiveHidden($0)
18 | self.reactiveHiddenDidChange()
19 | }.dispatchOnMainQueue()
20 | }
21 | }
22 |
23 | public func mapReactiveHidden(value: Bool) -> Bool {
24 | return value
25 | }
26 |
27 | public func reactiveHiddenDidChange() {}
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/Common/Foundation/String+vincerp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 05/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | public extension String {
7 |
8 | public var length: Index.Distance {
9 | return self.characters.count
10 | }
11 |
12 | public func trim() -> String {
13 | return self.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/Common/NSObject+vincerp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 14/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | extension NSObject {
7 |
8 | class func swizzleMethodSelector(origSelector: String!, withSelector: String!, forClass:AnyClass!) -> Bool {
9 |
10 | var originalMethod: Method?
11 | var swizzledMethod: Method?
12 |
13 | originalMethod = class_getInstanceMethod(forClass, Selector(origSelector))
14 | swizzledMethod = class_getInstanceMethod(forClass, Selector(withSelector))
15 |
16 | if (originalMethod != nil && swizzledMethod != nil) {
17 | if class_addMethod(forClass, Selector(origSelector), method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!)) {
18 | class_replaceMethod(forClass, Selector(withSelector), method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!));
19 | } else {
20 | method_exchangeImplementations(originalMethod!, swizzledMethod!)
21 | }
22 | return true
23 | }
24 | return false
25 | }
26 |
27 | class func swizzleStaticMethodSelector(origSelector: String!, withSelector: String!, forClass:AnyClass!) -> Bool {
28 |
29 | var originalMethod: Method?
30 | var swizzledMethod: Method?
31 |
32 | originalMethod = class_getClassMethod(forClass, Selector(origSelector))
33 | swizzledMethod = class_getClassMethod(forClass, Selector(withSelector))
34 |
35 | if (originalMethod != nil && swizzledMethod != nil) {
36 | method_exchangeImplementations(originalMethod!, swizzledMethod!)
37 | return true
38 | }
39 | return false
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/UIKit/UIActivityIndicatorView+vincerp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 27/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | public extension UIActivityIndicatorView {
9 |
10 | override public func reactiveHiddenDidChange() {
11 | if self.hidden {
12 | self.stopAnimating()
13 | } else {
14 | self.startAnimating()
15 | }
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/UIKit/UIButton+vincerp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 05/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | // TODO: Add tests for eventhandlers
9 | // TODO: move separate file
10 | public typealias ClickHandler = (UIButton) -> ()
11 |
12 | public class ClickHandlerAction: Dispatchable {
13 | let handler: ClickHandler
14 | var dispatchQueue: dispatch_queue_t!
15 |
16 | init(handler: ClickHandler) {
17 | self.handler = handler
18 | }
19 |
20 | func execute(button:UIButton) {
21 | self.handler(button)
22 | }
23 |
24 | public func dispatchOnQueue(dispatchQueue: dispatch_queue_t?) -> ClickHandlerAction {
25 | self.dispatchQueue = dispatchQueue
26 | return self
27 | }
28 |
29 | }
30 |
31 | public func definedAs(handler: ClickHandler) -> ClickHandlerAction {
32 | return ClickHandlerAction(handler: handler)
33 | }
34 |
35 | private var eventHandlers: [UIButton: ClickHandlerAction] = [UIButton: ClickHandlerAction]()
36 | private let clickHandlerMethodName = "onClick:"
37 |
38 | public extension UIButton {
39 |
40 | override public func mapReactiveEnabled(value: Bool) -> Bool {
41 | return value && !self.executing*
42 | }
43 |
44 | public var clickHandler: ClickHandlerAction? {
45 | get {
46 | return eventHandlers[self]
47 | }
48 |
49 | set {
50 | if let v = newValue {
51 | eventHandlers[self] = v
52 | self.executing <- false
53 | self.addTarget(self, action: Selector(clickHandlerMethodName), forControlEvents: .TouchUpInside)
54 | } else {
55 | eventHandlers.removeValueForKey(self)
56 | self.removeTarget(self, action: Selector(clickHandlerMethodName), forControlEvents: .TouchUpInside)
57 | }
58 | }
59 | }
60 |
61 | public func onClick(sender: UIButton) {
62 |
63 | dispatch_async(dispatch_get_main_queue(), {
64 | self.enabled = false
65 | self.executing <- true
66 | })
67 |
68 | let handler = eventHandlers[self]!
69 |
70 | if let q = handler.dispatchQueue {
71 | dispatch_async(q) {
72 | self.onClickThreadless(handler)
73 | }
74 | } else {
75 | self.onClickThreadless(handler)
76 | }
77 |
78 | }
79 |
80 | public func done() {
81 | dispatch_async(dispatch_get_main_queue(), {
82 | self.executing <- false
83 | self.enabled = true
84 | })
85 | }
86 |
87 | private func onClickThreadless(handler: ClickHandlerAction) {
88 | self.executing <- true
89 | handler.execute(self)
90 | }
91 |
92 | public var executing: Source {
93 | get {
94 | return reactiveSource(name: "executing", initValue: false)
95 | }
96 |
97 | set {
98 | }
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/UIKit/UIControl+vincerp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 27/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | public extension UIControl {
9 |
10 | public var reactiveEnabled: Hub {
11 | get {
12 | return reactiveSource(name: "enabled", initValue: self.enabled)
13 | }
14 |
15 | set {
16 | newValue.onChange {
17 | self.enabled = self.mapReactiveEnabled($0)
18 | self.reactiveEnabledDidChange()
19 | }.dispatchOnMainQueue()
20 | }
21 | }
22 |
23 | public func mapReactiveEnabled(value: Bool) -> Bool {
24 | return value
25 | }
26 |
27 | public func reactiveEnabledDidChange() {
28 | }
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/UIKit/UILabel+vincerp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 14/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | public extension UILabel {
9 |
10 | public var reactiveText: Hub {
11 | get {
12 | return reactiveProperty(forProperty: "text", initValue: self.text!)
13 | }
14 |
15 | set {
16 | newValue.onChange {
17 | self.text = $0
18 | }.dispatchOnMainQueue()
19 | }
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/UIKit/UIResponder+vincerp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Agnes Vasarhelyi on 30/10/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | public extension UIResponder {
9 |
10 | public func reactiveProperty(forProperty propertyName: String, initValue: T, initializer: ((Source) -> ())? = nil) -> Hub {
11 | return ReactivePropertyGenerator.property(self, propertyName: propertyName, initValue: initValue, initializer: initializer)
12 | }
13 |
14 | public func reactiveSource(name propertyName: String, initValue: T) -> Source {
15 | return ReactivePropertyGenerator.source(self, propertyName: propertyName, initValue: initValue)
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/UIKit/UISearchBar+didChange.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 26/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | private typealias EventHandler = (UISearchBar) -> ()
9 | private var eventHandlers = [UISearchBar: [EventHandler]]()
10 |
11 | extension UISearchBar {
12 |
13 | public func addChangeHandler(actionBlock: (UISearchBar) -> ()) {
14 | if let handlers = eventHandlers[self] {
15 | eventHandlers[self] = handlers.arrayByAppending(actionBlock)
16 | } else {
17 | eventHandlers[self] = [actionBlock]
18 | }
19 | self.delegate = self
20 | }
21 |
22 | }
23 |
24 | // TODO: add removeChangeHandler
25 | extension UISearchBar : UISearchBarDelegate {
26 |
27 | public func searchBar(sender: UISearchBar, textDidChange searchText: String) {
28 | if let handlers = eventHandlers[sender] {
29 | for handler in handlers {
30 | handler(sender)
31 | }
32 | }
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/UIKit/UISearchBar+vincerp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 16/10/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import UIKit
7 | import ObjectiveC
8 |
9 | extension UISearchBar {
10 |
11 | public var reactiveText: Hub {
12 | get {
13 | return reactiveProperty(forProperty: "text", initValue: self.text!) { emitter in
14 | self.addChangeHandler() { textField in
15 | emitter <- textField.text!
16 | }
17 | }
18 | }
19 |
20 | set {
21 | newValue.onChange {
22 | self.text = $0
23 | }.dispatchOnMainQueue()
24 | }
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/UIKit/UIStepper+vincerp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 14/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | public extension UIStepper {
9 |
10 | public var reactiveValue: Hub {
11 | get {
12 | return reactiveProperty(forProperty: "value", initValue: self.value)
13 | }
14 |
15 | set {
16 | newValue.onChange {
17 | self.value = $0
18 | }.dispatchOnMainQueue()
19 | }
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/UIKit/UITextField+didChange.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 26/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | private typealias EventHandler = (UITextField) -> ()
9 | private var eventHandlers = [UITextField: [EventHandler]]()
10 |
11 | extension UITextField {
12 |
13 | public func addChangeHandler(actionBlock: (UITextField) -> ()) {
14 | if let handlers = eventHandlers[self] {
15 | eventHandlers[self] = handlers.arrayByAppending(actionBlock)
16 | } else {
17 | eventHandlers[self] = [actionBlock]
18 | }
19 |
20 | self.addTarget(self, action: Selector("eventHandler:"), forControlEvents: .EditingChanged)
21 | }
22 |
23 | // TODO: add removeChangeHandler
24 | public func eventHandler(sender: UITextField) {
25 | if let handlers = eventHandlers[sender] {
26 | for handler in handlers {
27 | handler(sender)
28 | }
29 | }
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/UIKit/UITextField+vincerp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 05/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | extension UITextField {
9 |
10 | public var reactiveText: Hub {
11 | get {
12 | return reactiveProperty(forProperty: "text", initValue: self.text!) { emitter in
13 | self.addChangeHandler() { textField in
14 | emitter <- textField.text!
15 | }
16 | }
17 | }
18 |
19 | set {
20 | newValue.onChange {
21 | self.text = $0
22 | }.dispatchOnMainQueue()
23 | }
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Extension/UIKit/UIView+vincerp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 27/09/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import UIKit
7 |
8 | public extension UIView {
9 |
10 | public var reactiveHidden: Hub {
11 | get {
12 | return reactiveProperty(forProperty: "hidden", initValue: true)
13 | }
14 |
15 | set {
16 | newValue.onChange {
17 | self.hidden = self.mapReactiveHidden($0)
18 | self.reactiveHiddenDidChange()
19 | }.dispatchOnMainQueue()
20 | }
21 | }
22 |
23 | public func mapReactiveHidden(value: Bool) -> Bool {
24 | return value
25 | }
26 |
27 | public func reactiveHiddenDidChange() {
28 | }
29 |
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | v0.1.3
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/UpdateState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belényesi on 01/12/15.
3 | // Copyright © 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | private let globalID = AtomicLong(0)
7 |
8 | public func nextID() -> long {
9 | return globalID.getAndIncrement()
10 | }
11 |
12 | public struct UpdateState {
13 |
14 | let id: long
15 | let value: Try
16 | let parents: Set
17 | let level: long
18 |
19 | init(_ parents: Set, _ level: long, _ timestamp: long, _ value: Try) {
20 | self.parents = parents
21 | self.level = level
22 | self.id = timestamp
23 | self.value = value
24 | }
25 |
26 | init(_ value: Try) {
27 | self.init(nextID(), value)
28 | }
29 |
30 | init(_ timestamp: long, _ value: Try) {
31 | self.init(Set(), 0, nextID(), value)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerp/vincerp.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | #import
7 |
8 | //! Project version number for VinceRP.
9 | FOUNDATION_EXPORT double VinceRPVersionNumber;
10 |
11 | //! Project version string for VinceRP.
12 | FOUNDATION_EXPORT const unsigned char VinceRPVersionString[];
13 |
14 | // In this header, you should import all the public headers of your framework using statements like #import
15 |
16 | #import "VRPNSObjectHelper.h"
17 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerpTests/Common/AdvancedSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | @testable import VinceRP
7 |
8 | import Quick
9 | import Nimble
10 |
11 | func myRandom() -> Int {
12 | return Int(arc4random())
13 | }
14 |
15 | let fakeError = NSError(domain: "domain.com", code: 1, userInfo: nil)
16 |
17 | class AdvancedSpec: QuickSpec {
18 |
19 | override func spec() {
20 |
21 | describe("advanced") {
22 | /*
23 | context("performance") {
24 |
25 | it("init") {
26 | // given
27 | let start = CACurrentMediaTime()
28 | var n = 0
29 |
30 | // when
31 | while CACurrentMediaTime() < start + 1.0 {
32 | let (_, _, _, _, _, _) = testGraph()
33 | n += 1
34 | }
35 |
36 | // then
37 | expect(n) > 30000
38 | }
39 |
40 | it("propagation") {
41 | // given
42 | let (a, b, c, d, e, f) = testGraph()
43 | let start = CACurrentMediaTime()
44 | var n = 0
45 |
46 | // when
47 | while CACurrentMediaTime() < start + 1.0 {
48 | a <- n
49 | n += 1
50 | }
51 |
52 | // then
53 | expect(n) > 9500.0
54 | }
55 |
56 | }
57 | */
58 |
59 | context("nesting") {
60 |
61 | it("works with nested reactives") {
62 | // given
63 | let a = reactive(1)
64 | let b = definedAs {
65 | (definedAs{ a* }, definedAs{ myRandom() })
66 | }
67 | let r = b*.1*
68 |
69 | // when
70 | a <- 2
71 |
72 | // then
73 | expect(b*.1*) =~ r
74 | }
75 |
76 | it("works with recalcs") {
77 | // given
78 | var source = 0
79 | let a = definedAs{source}
80 | var i = 0
81 | _ = onChangeDo(a){ _ in
82 | i += 1
83 | }
84 |
85 | // then
86 | expect(i) =~ 1
87 | expect(a*) =~ 0
88 |
89 | // when
90 | source = 1
91 |
92 | // then
93 | expect(a*) =~ 0
94 |
95 | // when
96 | a.recalc()
97 |
98 | // then
99 | expect(a*) =~ 1
100 | expect(i) =~ 2
101 | }
102 |
103 | it("can update multiple variables in a batch") {
104 | // given
105 | let a = reactive(1)
106 | let b = reactive(1)
107 | let c = reactive(1)
108 | let d = definedAs {
109 | a* + b* + c*
110 | }
111 | var i = 0
112 |
113 | // when
114 | _ = onChangeDo(d) { _ in
115 | i += 1
116 | }
117 |
118 | // then
119 | expect(i) =~ 1
120 | a <- 2
121 | expect(i) =~ 2
122 | b <- 2
123 | expect(i) =~ 3
124 | c <- 2
125 | expect(i) =~ 4
126 |
127 | BatchUpdate(a, withValue:3).and(b, withValue:3).and(c, withValue:3).now()
128 |
129 | expect(i) =~ 5
130 |
131 | BatchUpdate(a, withValue:4).and(b, withValue:5).and(c, withValue:6).now()
132 |
133 | expect(i) =~ 6
134 | expect(a*) =~ 4
135 | expect(b*) =~ 5
136 | expect(c*) =~ 6
137 | }
138 |
139 | }
140 |
141 | }
142 |
143 | describe("combinators") {
144 |
145 | it("blocks observers") {
146 | // given
147 | let a = reactive(10)
148 | let b = a.filter {
149 | $0 > 5
150 | }
151 | var sideeffect = 0
152 | onChangeDo(b) { _ in
153 | sideeffect = sideeffect + 1
154 | }
155 |
156 | // when
157 | a <- 1
158 |
159 | // then
160 | expect(b*) =~ 10
161 | expect(sideeffect) =~ 1
162 |
163 | // when
164 | a <- 2
165 |
166 | // then
167 | expect(b*) =~ 10
168 | expect(sideeffect) =~ 1
169 |
170 | // when
171 | a <- 6
172 |
173 | // then
174 | expect(b*) =~ 6
175 | expect(sideeffect) =~ 2
176 | }
177 |
178 | }
179 |
180 | context("kill") {
181 |
182 | it("kills observer") {
183 | // given
184 | let a = reactive(1)
185 | let b = definedAs { 2 * a* }
186 | var target = 0
187 | let o = onChangeDo(b) { _ in
188 | target = b*
189 | }
190 |
191 | // then
192 | expect(a.children) =~ toSet(b)
193 | expect(b.children) =~ toSet(o)
194 | expect(target) =~ 2
195 |
196 | // when
197 | a <- 2
198 |
199 | // then
200 | expect(target) =~ 4
201 |
202 | // when
203 | o.kill()
204 |
205 | // then
206 | expect(a.children) =~ toSet(b)
207 | expect(b.children) =~ Set()
208 |
209 | // when
210 | a <- 3
211 |
212 | // then
213 | expect(target) =~ 4
214 | }
215 |
216 | it("kills reactive") {
217 | // given
218 | let (a, b, c, d, e, f) = testGraph()
219 |
220 | // then
221 | expect(c*) =~ 2
222 | expect(e*) =~ 1
223 | expect(f*) =~ 10
224 |
225 | // when
226 | a <- 3
227 |
228 | // then
229 | expect(c*) =~ 6
230 | expect(e*) =~ 3
231 | expect(f*) =~ 12
232 |
233 | // when
234 | d.kill()
235 | a <- 1
236 |
237 | // then
238 | expect(f*) =~ 14
239 | expect(e.children) =~ toSet(f)
240 |
241 | // when
242 | f.kill()
243 |
244 | // then
245 | expect(e.children) =~ Set()
246 |
247 | // when
248 | a <- 3
249 |
250 | // then
251 | expect(c*) =~ 6
252 | expect(e*) =~ 3
253 | expect(f*) =~ 14
254 | expect(a.children) =~ toSet(c)
255 | expect(b.children) =~ toSet(c)
256 |
257 | // when
258 | c.kill()
259 |
260 | // then
261 | expect(a.children) =~ Set()
262 | expect(b.children) =~ Set()
263 |
264 | // when
265 | a <- 1
266 |
267 | // then
268 | expect(c*) =~ 6
269 | expect(e*) =~ 3
270 | expect(f*) =~ 14
271 | }
272 |
273 |
274 | it("kills all Hub") {
275 | // given
276 | let (a, _, c, d, e, f) = testGraph()
277 |
278 | // when
279 | // killAll-ing d makes f die too
280 | d.killAll()
281 |
282 | // then
283 | a <- 3
284 | expect(c*) =~ 6
285 | expect(e*) =~ 3
286 | expect(f*) =~ 10
287 | }
288 | }
289 |
290 | }
291 |
292 | }
293 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerpTests/Common/Core/Hub+operatorsSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 11/26/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | @testable import VinceRP
7 |
8 | import Quick
9 | import Nimble
10 |
11 | class HubOperatorsSpec: QuickSpec {
12 |
13 | override func spec() {
14 |
15 | it("should negate") {
16 | // given
17 | let x = reactive(true)
18 |
19 | // when
20 | expect(x.value()) == true
21 |
22 | // then
23 | expect(x.not()*) == false
24 | }
25 |
26 | it("can skip errors") {
27 | // given
28 | let x = reactive(1)
29 | let y = definedAs { x* + 1 }.skipErrors()
30 | var count = 0
31 | onErrorDo(y) { _ in
32 | count++
33 | }
34 |
35 | // when
36 | x <- fakeError
37 |
38 | // then
39 | expect(count) == 0
40 | }
41 |
42 | it("works with foreach") {
43 | // given
44 | let x = reactive(1)
45 | var history = [Int]()
46 |
47 | // when
48 | x.foreach {
49 | history.append(2 * $0)
50 | }
51 |
52 | // then
53 | expect(history).toEventually(equal([2]))
54 |
55 | // when
56 | x <- 2
57 |
58 | // then
59 | expect(history).toEventually(equal([2, 4]))
60 | }
61 |
62 |
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerpTests/Common/Core/MapperSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 11/27/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | @testable import VinceRP
7 |
8 | import Quick
9 | import Nimble
10 |
11 | class MapperSpec: QuickSpec {
12 |
13 | override func spec() {
14 |
15 | it("can map values") {
16 | // given
17 | let x = reactive(10)
18 | let y = definedAs { x* + 2 }
19 | let z = x.map { $0 * 2 }
20 | let s = y.map { $0 + 3 }
21 |
22 | // then
23 | expect(z*) =~ 20
24 | expect(s*) =~ 15
25 |
26 | // when
27 | x <- 1
28 |
29 | // then
30 | expect(z*) =~ 2
31 | expect(s*) =~ 6
32 | }
33 |
34 | it("handles division by zero") {
35 | // given
36 | let numerator = reactive(4)
37 | let denominator = reactive(1)
38 |
39 | let frac = definedAs {
40 | (numerator*, denominator*)
41 | }.mapAll { (p:Try<(Int, Int)>) -> Try in
42 | switch p {
43 | case .Success(let value):
44 | let (n, d) = value
45 | if d == 0 {
46 | return Try(NSError(domain: "division by zero", code: -0, userInfo: nil))
47 | }
48 | return Try(n/d)
49 | case .Failure(let error): return Try(error)
50 | }
51 | }
52 |
53 | expect(frac*) =~ 4
54 |
55 | // when
56 | denominator <- 0
57 |
58 | // then
59 | expect(frac.toTry().isFailure()).toEventually(beTrue())
60 |
61 | // when
62 | denominator <- 2
63 |
64 | // then
65 | expect(frac.toTry().isSuccess()).toEventually(beTrue())
66 | expect(frac*) =~ 2
67 | }
68 |
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerpTests/Common/Core/ReducerSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 11/27/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | @testable import VinceRP
7 |
8 | import Quick
9 | import Nimble
10 |
11 | class ReducerSpec: QuickSpec {
12 |
13 | override func spec() {
14 |
15 | it("filters") {
16 | // given
17 | let x = reactive(10)
18 | let y = x.filter { $0 > 5 }
19 |
20 | // when
21 | x <- 1
22 |
23 | // then
24 | expect(y*) == 10
25 |
26 | // when
27 | x <- 6
28 |
29 | // then
30 | expect(y*) =~ 6
31 |
32 | // when
33 | x <- 2
34 |
35 | // then
36 | expect(y*) == 6
37 |
38 | // when
39 | x <- 19
40 |
41 | // then
42 | expect(y*) =~ 19
43 | }
44 |
45 | it("filters all") {
46 | // given
47 | let x = reactive(10)
48 | let y = definedAs { 100 / x* }
49 | let z = y.filterAll { $0.isSuccess() }
50 |
51 | // then
52 | expect(z*) == 10
53 |
54 | // when
55 | x <- 9
56 |
57 | // then
58 | expect(z*) =~ 11
59 |
60 | // when
61 | x <- fakeError
62 |
63 | // then
64 | expect(z*) == 11
65 |
66 | // when
67 | x <- 1
68 |
69 | // then
70 | expect(z*) =~ 100
71 | }
72 |
73 | it("reduces") {
74 | // given
75 | let x = reactive(1)
76 | let y = x.reduce { $0 * $1 }
77 |
78 | // when
79 | x <- 2
80 | expect(y*) =~ 2
81 |
82 | // when
83 | x <- 3
84 | expect(y*) =~ 6
85 |
86 | // when
87 | x <- 4
88 | expect(y*) =~ 24
89 | }
90 |
91 | it("reduces all") {
92 | // given
93 | let x = reactive(0)
94 | let sum = x.reduceAll { (x, y) in
95 | switch (x.value, y) {
96 | case (.Success(let a), .Success(let b)): return Try(a + b)
97 | default: return Try(0)
98 | }
99 | }
100 |
101 | // then
102 | expect(sum*) == 0
103 |
104 | // when
105 | x <- 1
106 |
107 | // then
108 | expect(sum*) =~ 1
109 |
110 | // when
111 | x <- 2
112 |
113 | // then
114 | expect(sum*) =~ 3
115 |
116 | // when
117 | x <- fakeError
118 |
119 | // then
120 | expect(sum*) =~ 0
121 |
122 | // when
123 | x <- 5
124 |
125 | // then
126 | expect(sum*) =~ 5
127 | }
128 |
129 | }
130 |
131 | }
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerpTests/Common/Core/ThrottleSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 11/27/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | @testable import VinceRP
7 |
8 | import Quick
9 | import Nimble
10 |
11 | class ThrottleSpec: QuickSpec {
12 |
13 | override func spec() {
14 |
15 | it("waits") {
16 | // given
17 | let x = reactive(0)
18 | let y = x.throttle(0.1)
19 |
20 | // then
21 | expect(y*) =~ 0
22 |
23 | // when
24 | x <- 1
25 |
26 | // then
27 | expect(y*) =~ 0
28 |
29 | // then
30 | expect(y*) =~ 1
31 | }
32 |
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerpTests/Common/SmokeSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | @testable import VinceRP
7 |
8 | import Quick
9 | import Nimble
10 |
11 | func function(a: Int) -> Int {
12 | return 3 + a
13 | }
14 |
15 | class SmokeSpec: QuickSpec {
16 |
17 | override func spec() {
18 |
19 | describe("basic") {
20 |
21 | context("reactive variable") {
22 |
23 | it("holds the initial value") {
24 | // given
25 | let a = reactive(1)
26 |
27 | // then
28 | expect(a*) =~ 1
29 | }
30 |
31 | it("updates it's value") {
32 | // given
33 | let a = reactive(1)
34 |
35 | // when
36 | a <- 6
37 |
38 | // then
39 | expect(a*) =~ 6
40 | }
41 |
42 | it("updates it's value using double arrow") {
43 | // given
44 | let a = reactive(1)
45 |
46 | // when
47 | a <- 6 <- 3
48 |
49 | // then
50 | expect(a*) =~ 3
51 | }
52 |
53 | it("updates it's value from a function") {
54 | // given
55 | let a = reactive(1)
56 |
57 | // when
58 | a <- function(1)
59 |
60 | // then
61 | expect(a*) =~ 4
62 | }
63 |
64 | }
65 |
66 | context("reactive hub") {
67 |
68 | it("calculates it's value initially") {
69 | // given
70 | let a = reactive(1)
71 | let b = reactive(2)
72 |
73 | // when
74 | let c = definedAs {
75 | a* + b*
76 | }
77 |
78 | // then
79 | expect(c*) =~ 3
80 | }
81 |
82 | it("updates it's value on parent gets update") {
83 |
84 | // given
85 | let a = reactive(1)
86 | let b = reactive(2)
87 | let c = definedAs {
88 | a* + b*
89 | }
90 |
91 | // when
92 | a <- 2
93 |
94 | // then
95 | expect(c*) =~ 4
96 |
97 | }
98 |
99 | it("updates it's value on parents get update") {
100 | // given
101 | let a = reactive(1)
102 | let b = reactive(2)
103 | let c = definedAs {
104 | a* + b*
105 | }
106 |
107 | // when
108 | a <- 2
109 | b <- 3
110 |
111 | // then
112 | expect(c*) =~ 5
113 | }
114 |
115 | }
116 |
117 | context("side effect") {
118 |
119 | it("runs sideeffect initially") {
120 | // given
121 | let a = reactive(1)
122 | var counter = 0
123 |
124 | // when
125 | _ = onChangeDo(a) { _ in
126 | counter++
127 | }
128 |
129 | // then
130 | expect(counter) =~ 1
131 | }
132 |
133 | it("runs sideeffect when parent gets update") {
134 | // given
135 | let a = reactive(1)
136 |
137 | var counter = 0
138 | _ = onChangeDo(a) { _ in
139 | counter++
140 | }
141 |
142 | // when
143 | a <- 2
144 |
145 | // then
146 | expect(counter) =~ 2
147 | }
148 |
149 | it("runs sideeffect on hub gets update") {
150 | // given
151 | let a = reactive(1)
152 | let b = reactive(2)
153 | let c = definedAs {
154 | "test\(a*)+\(b*)"
155 | }
156 | var counter = 0
157 | _ = onChangeDo(c) { _ in
158 | counter++
159 | }
160 |
161 | // when
162 | a <- 8
163 | expect(c*) =~ "test8+2"
164 | b <- 6
165 |
166 | // then
167 | expect(c*) =~ "test8+6"
168 | expect(counter) =~ 3
169 | }
170 |
171 | it("runs sideeffect on complex") {
172 | // given
173 | let a = reactive(1)
174 | let b = reactive(2)
175 | let e = reactive("buda")
176 | let c = definedAs {
177 | "pest=\(a*)+\(b*)"
178 | }
179 | let f = definedAs {
180 | e* + c*
181 | }
182 | var counter = 0
183 | _ = onChangeDo(c) { _ in
184 | counter++
185 | }
186 |
187 | // when
188 | a <- 8
189 |
190 | expect(c*) =~ "pest=8+2"
191 |
192 | b <- 6
193 |
194 | // then
195 | expect(c*) =~ "pest=8+6"
196 | expect(f*) =~ "budapest=8+6"
197 | expect(counter) =~ 3
198 | }
199 |
200 | it("is happy without default value") {
201 | // given
202 | let a: Source = reactive()
203 |
204 | // then
205 | expect(a.hasValue()) =~ false
206 |
207 | // when
208 | a <- 1
209 |
210 | // then
211 | expect(a*) =~ 1
212 | expect(a.hasValue()) =~ true
213 |
214 | // when
215 | a <- fakeError
216 |
217 | // then
218 | expect(a.hasValue()) =~ true
219 | }
220 |
221 |
222 | it("is works with optionals") {
223 | // given
224 | let a: Source = reactive(1)
225 |
226 | // then
227 | expect(a*) =~ 1
228 |
229 | // when
230 | a <- nil
231 |
232 | // then
233 | expect(a*).to(beNil())
234 |
235 | // when
236 | a <- fakeError
237 |
238 | // then
239 | expect(a.toTry().isFailure()) =~ true
240 | }
241 |
242 | }
243 |
244 | }
245 |
246 | }
247 |
248 | }
249 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerpTests/Common/Threading/DynamicVariableSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 18/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | @testable import VinceRP
7 |
8 | import Quick
9 | import Nimble
10 |
11 | class Runnable {
12 | typealias Closure = () -> ()
13 | let closure: Closure
14 | let name: String
15 |
16 | init(_ name:String, _ closure: Closure) {
17 | self.name = name
18 | self.closure = closure
19 | }
20 |
21 | @objc func run() {
22 | NSThread.currentThread().name = self.name
23 | self.closure()
24 | }
25 |
26 | func start() {
27 | let thread = NSThread(target:self, selector:"run", object:nil)
28 | thread.start()
29 | }
30 | }
31 |
32 | class DynamicVariableSpec: QuickSpec {
33 |
34 | override func spec() {
35 |
36 | describe("dynamic variable") {
37 |
38 | var dyn: DynamicVariable!
39 | var doSomething: (() -> String)!
40 | var r1: String!
41 | var r2: String!
42 |
43 | beforeEach {
44 | dyn = DynamicVariable(0)
45 | doSomething = {
46 | guard let v = dyn.value else {
47 | return ""
48 | }
49 | return "\(NSThread.currentThread().name!): \(v)"
50 | }
51 | r1 = nil
52 | r2 = nil
53 |
54 | }
55 |
56 | it("ensures the different context for different threads") {
57 | // when
58 | Runnable("thread-1") {
59 | r1 = dyn.withValue(10, doSomething)
60 | }.start()
61 |
62 | Runnable("thread-2") {
63 | r2 = dyn.withValue(20, doSomething)
64 | }.start()
65 |
66 | // then
67 | expect(r1).toEventually(equal("thread-1: 10"))
68 | expect(r2).toEventually(equal("thread-2: 20"))
69 | }
70 |
71 | it("shares the same variable in same thread") {
72 | // when
73 | Runnable("thread-1") {
74 | r1 = dyn.withValue(10, doSomething)
75 | r2 = dyn.withValue(20, doSomething)
76 | }.start()
77 |
78 | // then
79 | expect(r1).toEventually(equal("thread-1: 10"))
80 | expect(r2).toEventually(equal("thread-1: 20"))
81 | }
82 |
83 | // This test does not pass since there is no hiearchy between NSThreads
84 | // So you cannot inherit the parent thread's dynvalue :-(
85 | // That is the difference between ThreadLocal and InheritedThreadLocal
86 |
87 | /*
88 | it("passes the value to the embedded thread") {
89 | // when
90 | dyn.withValue(10) { () -> String in
91 | Runnable("thread-1") {
92 | r1 = doSomething()
93 | }.start()
94 | Runnable("thread-2") {
95 | r2 = doSomething()
96 | }.start()
97 | return ""
98 | }
99 |
100 | // then
101 | expect(r1).toEventually(equal("thread-1: 10"))
102 | expect(r2).toEventually(equal("thread-2: 10"))
103 | }
104 | */
105 | }
106 |
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerpTests/Common/Util/FunctionalArraySpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 21/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import Quick
7 | import Nimble
8 |
9 | class FunctionalArraySpec: QuickSpec {
10 |
11 | override func spec() {
12 |
13 | describe("prepend") {
14 |
15 | it("prepends to non-empty array") {
16 | // given
17 | let s = [1, 2]
18 |
19 | // when
20 | let r = s.arrayByPrepending(0)
21 |
22 | // then
23 | expect(r) == [0, 1, 2]
24 | }
25 |
26 | it("prepends to empty array") {
27 | // given
28 | let s = [Int]()
29 |
30 | // when
31 | let r = s.arrayByPrepending(0)
32 |
33 | // then
34 | expect(r) == [0]
35 | }
36 |
37 | }
38 |
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerpTests/Common/Util/FunctionalDictionarySpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 21/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | import Quick
7 | import Nimble
8 |
9 | class FunctionalDictionarySpec: QuickSpec {
10 |
11 | override func spec() {
12 |
13 | describe("mapValues") {
14 |
15 | it("maps empty dic to empty dic") {
16 | // given
17 | let s = Dictionary()
18 |
19 | // when
20 | let r = s.mapValues{$0*2}
21 |
22 | // then
23 | expect(r.count) == 0
24 | }
25 |
26 | it("maps values correctly") {
27 | // given
28 | let s:Dictionary = [1:1, 2:2, 3:3]
29 |
30 | // when
31 | let r = s.mapValues{$0*2}
32 |
33 | // then
34 | expect(r) == [1:2, 2:4, 3:6]
35 | }
36 |
37 | }
38 |
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerpTests/Common/Util/FunctionalSetSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 21/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | @testable import VinceRP
7 |
8 | import Quick
9 | import Nimble
10 |
11 | class FunctionalSetSpec: QuickSpec {
12 |
13 | override func spec() {
14 |
15 | context("filter") {
16 |
17 | it("filters something") {
18 | // given
19 | let s = toSet(1, 2, 3)
20 |
21 | // when
22 | let r = s.filter{$0 > 2}
23 |
24 | // then
25 | expect(r) == toSet(3)
26 | }
27 |
28 | it("filters nothing") {
29 | // given
30 | let s = toSet(1, 2, 3)
31 |
32 | // when
33 | let r = s.filter{$0 > 3}
34 |
35 | // then
36 | expect(r.count) == 0
37 | }
38 |
39 | }
40 |
41 | context("foreach") {
42 |
43 | it("does nothing on empty set") {
44 | // given
45 | var r = 0
46 | let s = Set()
47 |
48 | // when
49 | s.forEach {r = r + $0}
50 |
51 | // then
52 | expect(r) == 0
53 | }
54 |
55 | it("sums the members of the set") {
56 | // given
57 | var r = 0
58 | let s = toSet(1, 2, 3)
59 |
60 | // when
61 | s.forEach {r = r + $0}
62 |
63 | // then
64 | expect(r) == 6
65 | }
66 |
67 | }
68 |
69 | context("exists") {
70 |
71 | it("finds if exists") {
72 | // given
73 | let s = toSet(1, 2, 3)
74 |
75 | // when
76 | let r = s.hasElementPassingTest{$0 > 2}
77 |
78 | // then
79 | expect(r) == true
80 | }
81 |
82 | it("finds nothing") {
83 | // given
84 | let s = toSet(1, 2, 3)
85 |
86 | // when
87 | let r = s.hasElementPassingTest{$0 > 3}
88 |
89 | // then
90 | expect(r) == false
91 | }
92 |
93 | }
94 |
95 | context("map") {
96 |
97 | it("maps empty to empty") {
98 | // given
99 | let s = Set()
100 |
101 | // when
102 | let r = s.map{$0 * 2}
103 |
104 | // then
105 | expect(r.count) == 0
106 | }
107 |
108 | it("maps every item") {
109 | // given
110 | let s = toSet(1, 2, 3)
111 |
112 | // when
113 | let r = s.map{$0 * 2}
114 |
115 | // then
116 | expect(r) == toSet(2, 4, 6)
117 | }
118 |
119 | }
120 |
121 | context("min") {
122 |
123 | it("returns 0 if empty set") {
124 | // given
125 | let s: Set = Set()
126 |
127 | // when
128 | let r = s.min(0)
129 |
130 | // then
131 | expect(r) == 0
132 | }
133 |
134 | it("maps every item") {
135 | // given
136 | let s: Set = toSet(3, 1, 2)
137 |
138 | // when
139 | let r = s.min(0)
140 |
141 | // then
142 | expect(r) == 1
143 | }
144 |
145 | }
146 |
147 | context("partition") {
148 |
149 | it("returns empty tuple of sets if empty set") {
150 | // given
151 | let s = Set()
152 |
153 | // when
154 | let (r1, r2) = s.partition{$0 % 2 == 0}
155 |
156 | // then
157 | expect(r1.count) == 0
158 | expect(r2.count) == 0
159 | }
160 |
161 | it("returns 2 sets") {
162 | // given
163 | let s = toSet(3, 1, 2)
164 |
165 | // when
166 | let (r1, r2) = s.partition{$0 % 2 == 0}
167 |
168 | // then
169 | expect(r1) == toSet(2)
170 | expect(r2) == toSet(1, 3)
171 | }
172 |
173 | }
174 |
175 |
176 | context("groupBy") {
177 |
178 | it("returns emptyMap if empty map") {
179 | // given
180 | let s = Set()
181 |
182 | // when
183 | let r = s.groupBy{$0 % 2}
184 |
185 | // then
186 | expect(r.count) == 0
187 | }
188 |
189 | it("returns 2 sets") {
190 | // given
191 | let s = toSet(3, 1, 2)
192 |
193 | // when
194 | let r = s.groupBy{$0 % 2}
195 |
196 | // then
197 | expect(r) == [0 : toSet(2), 1 : toSet(1, 3)]
198 | }
199 |
200 | }
201 |
202 | context("flattenMap") {
203 |
204 | it("flattens empty set to empty set") {
205 | // given
206 | let s = Set()
207 |
208 | // when
209 | let r = s.flatMap{c in toSet(c)}
210 |
211 | // then
212 | expect(r.count) == 0
213 | }
214 |
215 | it("flattens flat set to flat set") {
216 | // given
217 | let s = toSet(3, 1, 2)
218 |
219 | // when
220 | let r = s.flatMap{c in toSet(c * 2)}
221 |
222 | // then
223 | expect(r) == toSet(6, 4, 2)
224 | }
225 |
226 | it("flattens two level set to flat set") {
227 | // given
228 | let s = toSet(toSet(3, 1, 2), toSet(4, 5, 3))
229 |
230 | // when
231 | let r = s.flatMap{c in c}
232 |
233 | // then
234 | expect(r) == toSet(1, 2, 3, 4, 5)
235 | }
236 |
237 | }
238 |
239 | context("flatten") {
240 |
241 | it("flattens empty set to empty set") {
242 | // given
243 | let s = Set()
244 |
245 | // when
246 | let r = s.flatten()
247 |
248 | // then
249 | expect(r.count) == 0
250 | }
251 |
252 | it("flattens flat set to flat set") {
253 | // given
254 | let s = toSet(3, 1, 2)
255 |
256 | // when
257 | let r = s.flatten()
258 |
259 | // then
260 | expect(r) == toSet(3, 2, 1)
261 | }
262 |
263 | it("flattens two level set to flat set") {
264 | // given
265 | let s = toSet(toSet(3, 1, 2), toSet(4, 5, 3))
266 |
267 | // when
268 | let r = s.flatten()
269 |
270 | // then
271 | expect(r) == toSet(1, 2, 3, 4, 5)
272 | }
273 |
274 | }
275 |
276 | }
277 |
278 | }
279 |
--------------------------------------------------------------------------------
/Carthage/Checkouts/VinceRP/vincerpTests/Common/Util/TrySpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Viktor Belenyesi on 20/04/15.
3 | // Copyright (c) 2015 Viktor Belenyesi. All rights reserved.
4 | //
5 |
6 | @testable import VinceRP
7 |
8 | import Quick
9 | import Nimble
10 |
11 | struct TestFailure {
12 | static let error = NSError(domain:"Wrappers Tests", code:100, userInfo:[NSLocalizedDescriptionKey:"Testing"])
13 | }
14 |
15 | class TrySpec: QuickSpec {
16 |
17 | override func spec() {
18 |
19 | describe("basic") {
20 |
21 | it("maps error to non-success") {
22 | // when
23 | let result = Try(false)
24 |
25 | // then
26 | expect(result.isSuccess()) == true
27 | }
28 |
29 | it("maps false to non-failure") {
30 | // when
31 | let result = Try(false)
32 |
33 | // then
34 | expect(result.isFailure()) == false
35 | }
36 |
37 |
38 | it("maps error to failure") {
39 | // when
40 | let result = Try(TestFailure.error)
41 |
42 | // then
43 | expect(result.isFailure()) == true
44 | }
45 |
46 | it("maps false to success") {
47 | // when
48 | let result = Try