Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Add ReactiveCocoa

  • Loading branch information...
commit 4bd4bf89a51bc8ba19718b0de0bf15c0f43b4c7a 1 parent df24770
Henrik Hodne authored
3  Podfile
... ...
@@ -1,2 +1,3 @@
1 1
 platform :osx, '10.7'
2  
-pod 'AFNetworking', '~> 1.0'
  2
+pod 'AFNetworking', '~> 1.0'
  3
+pod 'ReactiveCocoa', '~> 0.10.0'
24  Podfile.lock
... ...
@@ -1,11 +1,33 @@
1 1
 
2 2
 PODS:
3 3
 - AFNetworking (1.0.1)
  4
+- JRSwizzle (1.0)
  5
+- ReactiveCocoa (0.10.0):
  6
+  - ReactiveCocoa/Core (= 0.10.0)
  7
+  - ReactiveCocoa/RACExtensions (= 0.10.0)
  8
+- ReactiveCocoa/Core (0.10.0):
  9
+  - JRSwizzle (~> 1.0)
  10
+  - libextobjc/EXTConcreteProtocol (~> 0.2.3)
  11
+  - libextobjc/EXTKeyPathCoding (~> 0.2.3)
  12
+  - libextobjc/EXTScope (~> 0.2.3)
  13
+- ReactiveCocoa/RACExtensions (0.10.0):
  14
+  - ReactiveCocoa/Core
  15
+- libextobjc/EXTConcreteProtocol (0.2.3)
  16
+- libextobjc/EXTKeyPathCoding (0.2.3)
  17
+- libextobjc/EXTScope (0.2.3)
4 18
 
5 19
 DEPENDENCIES:
6 20
 - AFNetworking (~> 1.0)
  21
+- ReactiveCocoa (~> 0.10.0)
7 22
 
8 23
 SPEC CHECKSUMS:
9 24
   AFNetworking: 4c11f857c9a18d65f4257c90a1e74ac49f0ac422
  25
+  JRSwizzle: 6242ff38485d870fc2636899048ee1ab883ae587
  26
+  ReactiveCocoa: 1d0b1bca0092ca3088d7ae66799ce0116c25a612
  27
+  ReactiveCocoa/Core: 1d0b1bca0092ca3088d7ae66799ce0116c25a612
  28
+  ReactiveCocoa/RACExtensions: 1d0b1bca0092ca3088d7ae66799ce0116c25a612
  29
+  libextobjc/EXTConcreteProtocol: 7dcd66faf065d3b7fcb5f85a1646efaed28bcadf
  30
+  libextobjc/EXTKeyPathCoding: 7dcd66faf065d3b7fcb5f85a1646efaed28bcadf
  31
+  libextobjc/EXTScope: 7dcd66faf065d3b7fcb5f85a1646efaed28bcadf
10 32
 
11  
-COCOAPODS: 0.15.2
  33
+COCOAPODS: 0.16.0
31  src/AppDelegate.m
@@ -15,8 +15,9 @@
15 15
 #import "NotificationDisplayer.h"
16 16
 #import "TravisAPI.h"
17 17
 #import "RepositoryFilter.h"
  18
+#import <ReactiveCocoa/ReactiveCocoa.h>
18 19
 
19  
-@interface AppDelegate () <TravisEventFetcherDelegate, NSUserNotificationCenterDelegate>
  20
+@interface AppDelegate () <NSUserNotificationCenterDelegate>
20 21
 
21 22
 @property (strong) TravisEventFetcher *eventFetcher;
22 23
 @property (strong) NSStatusItem *statusItem;
@@ -31,8 +32,18 @@ - (void)applicationDidFinishLaunching:(NSNotification *)notification {
31 32
   [self setupGrowl];
32 33
   [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
33 34
 
34  
-  [self setEventFetcher:[[TravisEventFetcher alloc] init]];
35  
-  [[self eventFetcher] setDelegate:self];
  35
+  [self setEventFetcher:[TravisEventFetcher eventFetcher]];
  36
+  [[[[self eventFetcher] eventStream] filter:^(TravisEvent *event) {
  37
+    return [self shouldShowNotificationFor:event];
  38
+  }] subscribeNext:^(TravisEvent *event) {
  39
+    [[[TravisAPI standardAPI] fetchBuildWithID:[event buildID] forRepository:[event name]] subscribeNext:^(NSDictionary *build) {
  40
+      [event updateBuildInfo:build];
  41
+      Notification *notification = [Notification notificationWithEventData:event];
  42
+      [[NotificationDisplayer sharedNotificationDisplayer] deliverNotification:notification];
  43
+    } error:^(NSError *error) {
  44
+      NSLog(@"Couldn't get build info from JSON API. Error: %@.", error);
  45
+    }];
  46
+  }];
36 47
 
37 48
   [self setupStatusBarItem];
38 49
 }
@@ -77,20 +88,6 @@ - (BOOL)shouldShowNotificationFor:(TravisEvent *)eventData {
77 88
   return [filter acceptsRepository:[eventData name]];
78 89
 }
79 90
 
80  
-#pragma mark - TravisEventFetcherDelegate
81  
-
82  
-- (void)eventFetcher:(TravisEventFetcher *)eventFetcher gotEvent:(TravisEvent *)event {
83  
-  if ([self shouldShowNotificationFor:event]) {
84  
-    [[TravisAPI new] getBuildWithID:[event buildID] forRepository:[event name] success:^(NSDictionary *build) {
85  
-      [event updateBuildInfo:build];
86  
-      Notification *notification = [Notification notificationWithEventData:event];
87  
-      [[NotificationDisplayer sharedNotificationDisplayer] deliverNotification:notification];
88  
-    } failure:^(NSError *error) {
89  
-      NSLog(@"Couldn't get build info from JSON API. Error: %@.", error);
90  
-    }];
91  
-  }
92  
-}
93  
-
94 91
 #pragma mark - NSUserNotificationCenterDelegate
95 92
 
96 93
 - (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification {
10  src/TravisAPI.h
@@ -8,11 +8,15 @@
8 8
 
9 9
 #import <Foundation/Foundation.h>
10 10
 
11  
-typedef void (^BuildResponse)(NSDictionary *build);
12  
-typedef void (^FailureResponse)(NSError *error);
  11
+@class TravisHTTPClient;
  12
+@class RACSignal;
13 13
 
14 14
 @interface TravisAPI : NSObject
15 15
 
16  
-- (void)getBuildWithID:(NSNumber *)buildID forRepository:(NSString *)slug success:(BuildResponse)success failure:(FailureResponse)failure;
  16
++ (TravisAPI *)standardAPI;
  17
+
  18
+- (id)initWithHTTPClient:(TravisHTTPClient *)HTTPClient;
  19
+
  20
+- (RACSignal *)fetchBuildWithID:(NSNumber *)buildID forRepository:(NSString *)slug;
17 21
 
18 22
 @end
26  src/TravisAPI.m
@@ -9,16 +9,28 @@
9 9
 #import "TravisAPI.h"
10 10
 #import "TravisHTTPClient.h"
11 11
 
  12
+@interface TravisAPI ()
  13
+@property (nonatomic, strong) TravisHTTPClient *HTTPClient;
  14
+@end
  15
+
12 16
 @implementation TravisAPI
13 17
 
14  
-- (void)getBuildWithID:(NSNumber *)buildID forRepository:(NSString *)slug success:(BuildResponse)success failure:(FailureResponse)failure {
15  
-  NSString *path = [NSString stringWithFormat:@"/%@/builds/%@.json", slug, buildID];
  18
++ (TravisAPI *)standardAPI {
  19
+  return [[self alloc] initWithHTTPClient:[TravisHTTPClient standardHTTPClient]];
  20
+}
  21
+
  22
+- (id)initWithHTTPClient:(TravisHTTPClient *)HTTPClient {
  23
+  self = [super init];
  24
+  if (self == nil) return nil;
16 25
 
17  
-  [[TravisHTTPClient sharedHTTPClient] getPath:path parameters:nil success:^(AFHTTPRequestOperation *operation, NSDictionary *build) {
18  
-    if (success) success(build);
19  
-  } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
20  
-    if (failure) failure(error);
21  
-  }];
  26
+  _HTTPClient = HTTPClient;
  27
+
  28
+  return self;
  29
+}
  30
+
  31
+- (RACSignal *)fetchBuildWithID:(NSNumber *)buildID forRepository:(NSString *)slug {
  32
+  NSString *path = [NSString stringWithFormat:@"/%@/builds/%@.json", slug, buildID];
  33
+  return [[self HTTPClient] requestWithMethod:TravisHTTPClientMethodGET path:path parameters:nil];
22 34
 }
23 35
 
24 36
 @end
17  src/TravisEventFetcher.h
@@ -7,19 +7,10 @@
7 7
 //
8 8
 
9 9
 #import <Cocoa/Cocoa.h>
10  
-
11  
-@protocol TravisEventFetcherDelegate;
12  
-@class TravisEvent;
  10
+@class RACSignal;
13 11
 
14 12
 @interface TravisEventFetcher : NSObject
  13
+@property (readonly, strong) RACSignal *eventStream;
15 14
 
16  
-@property (weak) id<TravisEventFetcherDelegate> delegate;
17  
-
18  
-@end
19  
-
20  
-@protocol TravisEventFetcherDelegate <NSObject>
21  
-
22  
-@optional
23  
-- (void)eventFetcher:(TravisEventFetcher *)eventFetcher gotEvent:(TravisEvent *)event;
24  
-
25  
-@end
  15
++ (TravisEventFetcher *)eventFetcher;
  16
+@end
20  src/TravisEventFetcher.m
@@ -17,17 +17,23 @@
17 17
 #import "Reachability.h"
18 18
 #import "Notification.h"
19 19
 #import "NotificationDisplayer.h"
  20
+#import <ReactiveCocoa/ReactiveCocoa.h>
20 21
 
21 22
 @interface TravisEventFetcher () <PTPusherDelegate>
22 23
 
23 24
 @property (strong) PTPusher *pusher;
24 25
 @property (strong) PTPusherChannel *channel;
25 26
 @property (strong) Reachability *reachability;
  27
+@property (strong) RACReplaySubject *eventSubject;
26 28
 
27 29
 @end
28 30
 
29 31
 @implementation TravisEventFetcher
30 32
 
  33
++ (TravisEventFetcher *)eventFetcher {
  34
+  return [self new];
  35
+}
  36
+
31 37
 - (id)init {
32 38
   self = [super init];
33 39
   if (self) {
@@ -35,11 +41,21 @@ - (id)init {
35 41
     _channel = [_pusher subscribeToChannelNamed:kPusherChannelName];
36 42
     [_channel bindToEventNamed:kPusherEventBuildStarted target:self action:@selector(handleEvent:)];
37 43
     [_channel bindToEventNamed:kPusherEventBuildFinished target:self action:@selector(handleEvent:)];
  44
+    _eventSubject = [RACReplaySubject subject];
38 45
   }
39 46
   
40 47
   return self;
41 48
 }
42 49
 
  50
+- (RACSignal *)eventStream {
  51
+  return [[self eventSubject]
  52
+          map:^(PTPusherEvent *event) {
  53
+            return [[TravisEvent alloc] initWithEventData:[event data]];
  54
+          }];
  55
+}
  56
+
  57
+#pragma mark - PTPusherDelegate
  58
+
43 59
 - (void)pusher:(PTPusher *)client connectionDidConnect:(PTPusherConnection *)connection {
44 60
   [client setReconnectAutomatically:YES];
45 61
 }
@@ -80,9 +96,7 @@ - (void)reachabilityChanged:(NSNotification *)note {
80 96
 }
81 97
 
82 98
 - (void)handleEvent:(PTPusherEvent *)event {
83  
-  if ([[self delegate] respondsToSelector:@selector(eventFetcher:gotEvent:)]) {
84  
-    [[self delegate] eventFetcher:self gotEvent:[[TravisEvent alloc] initWithEventData:[event data]]];
85  
-  }
  99
+  [[self eventSubject] sendNext:event];
86 100
 }
87 101
 
88 102
 @end
21  src/TravisHTTPClient.h
@@ -6,10 +6,25 @@
6 6
 //  Copyright (c) 2012 Travis CI GmbH. All rights reserved.
7 7
 //
8 8
 
9  
-#import <AFNetworking/AFNetworking.h>
  9
+#import <Foundation/Foundation.h>
10 10
 
11  
-@interface TravisHTTPClient : AFHTTPClient
  11
+@class RACSignal;
12 12
 
13  
-+ (TravisHTTPClient *)sharedHTTPClient;
  13
+typedef NS_ENUM(NSInteger, TravisHTTPClientMethod) {
  14
+  TravisHTTPClientMethodGET,
  15
+  TravisHTTPClientMethodHEAD,
  16
+  TravisHTTPClientMethodPOST,
  17
+  TravisHTTPClientMethodPUT,
  18
+  TravisHTTPClientMethodDELETE,
  19
+  TravisHTTPClientMethodPATCH
  20
+};
  21
+
  22
+@interface TravisHTTPClient : NSObject
  23
+
  24
++ (TravisHTTPClient *)standardHTTPClient;
  25
+
  26
+- (id)initWithBaseURL:(NSURL *)baseURL;
  27
+
  28
+- (RACSignal *)requestWithMethod:(TravisHTTPClientMethod)method path:(NSString *)path parameters:(NSDictionary *)parameters;
14 29
 
15 30
 @end
65  src/TravisHTTPClient.m
@@ -7,31 +7,66 @@
7 7
 //
8 8
 
9 9
 #import "TravisHTTPClient.h"
  10
+#import <AFNetworking/AFNetworking.h>
  11
+#import <ReactiveCocoa/ReactiveCocoa.h>
10 12
 
11 13
 NSString * const kTravisBaseURL = @"http://travis-ci.org";
12 14
 
13  
-@implementation TravisHTTPClient
  15
+@interface TravisHTTPClient ()
  16
+@property (nonatomic, strong) AFHTTPClient *HTTPClient;
  17
+@end
14 18
 
15  
-+ (TravisHTTPClient *)sharedHTTPClient {
16  
-  static TravisHTTPClient *_sharedHTTPClient = nil;
17  
-  static dispatch_once_t onceToken;
18  
-  dispatch_once(&onceToken, ^{
19  
-    _sharedHTTPClient = [[TravisHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:kTravisBaseURL]];
20  
-  });
  19
+@implementation TravisHTTPClient
21 20
 
22  
-  return _sharedHTTPClient;
  21
++ (TravisHTTPClient *)standardHTTPClient {
  22
+  return [[self alloc] initWithBaseURL:[NSURL URLWithString:kTravisBaseURL]];
23 23
 }
24 24
 
25  
-- (id)initWithBaseURL:(NSURL *)url {
26  
-  self = [super initWithBaseURL:url];
27  
-  if (!self) {
28  
-    return nil;
29  
-  }
  25
+- (id)initWithBaseURL:(NSURL *)baseURL {
  26
+  self = [super init];
  27
+  if (self == nil) return nil;
30 28
 
31  
-  [self registerHTTPOperationClass:[AFJSONRequestOperation class]];
32  
-  [self setDefaultHeader:@"Accept" value:@"application/json"];
  29
+  [self setupHTTPClientWithBaseURL:baseURL];
33 30
 
34 31
   return self;
35 32
 }
36 33
 
  34
+- (void)setupHTTPClientWithBaseURL:(NSURL *)baseURL {
  35
+  [self setHTTPClient:[[AFHTTPClient alloc] initWithBaseURL:baseURL]];
  36
+  [[self HTTPClient] registerHTTPOperationClass:[AFJSONRequestOperation class]];
  37
+  [[self HTTPClient] setDefaultHeader:@"Accept" value:@"application/json"];
  38
+}
  39
+
  40
+- (RACSignal *)requestWithMethod:(TravisHTTPClientMethod)method path:(NSString *)path parameters:(NSDictionary *)parameters {
  41
+  RACReplaySubject *subject = [RACReplaySubject subject];
  42
+  NSURLRequest *request = [[self HTTPClient] requestWithMethod:[self methodStringForMethod:method] path:path parameters:parameters];
  43
+  AFHTTPRequestOperation *operation = [[self HTTPClient] HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
  44
+    [subject sendNext:responseObject];
  45
+    [subject sendCompleted];
  46
+  } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
  47
+    [subject sendError:error];
  48
+  }];
  49
+
  50
+  [[self HTTPClient] enqueueHTTPRequestOperation:operation];
  51
+
  52
+  return subject;
  53
+}
  54
+
  55
+- (NSString *)methodStringForMethod:(TravisHTTPClientMethod)method {
  56
+  switch (method) {
  57
+    case TravisHTTPClientMethodDELETE:
  58
+      return @"DELETE";
  59
+    case TravisHTTPClientMethodGET:
  60
+      return @"GET";
  61
+    case TravisHTTPClientMethodHEAD:
  62
+      return @"HEAD";
  63
+    case TravisHTTPClientMethodPATCH:
  64
+      return @"PATCH";
  65
+    case TravisHTTPClientMethodPOST:
  66
+      return @"POST";
  67
+    case TravisHTTPClientMethodPUT:
  68
+      return @"PUT";
  69
+  }
  70
+}
  71
+
37 72
 @end

0 notes on commit 4bd4bf8

Please sign in to comment.
Something went wrong with that request. Please try again.