From 157b0a1666395f6a985321b976cf26367e63dc7c Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sat, 3 Sep 2011 23:39:23 -0700 Subject: [PATCH] first commit --- .gitignore | 1 + Marshmallows.xcodeproj/project.pbxproj | 278 ++++++++++++++ .../contents.xcworkspacedata | 7 + Marshmallows/MMHTTPClient.h | 64 ++++ Marshmallows/MMHTTPClient.m | 355 ++++++++++++++++++ Marshmallows/Marshmallows-Prefix.pch | 7 + Marshmallows/Marshmallows.h | 12 + Marshmallows/NSDate+relative.h | 16 + Marshmallows/NSDate+relative.m | 60 +++ Marshmallows/NSString+sanity.h | 19 + Marshmallows/NSString+sanity.m | 76 ++++ 11 files changed, 895 insertions(+) create mode 100644 .gitignore create mode 100644 Marshmallows.xcodeproj/project.pbxproj create mode 100644 Marshmallows.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Marshmallows/MMHTTPClient.h create mode 100644 Marshmallows/MMHTTPClient.m create mode 100644 Marshmallows/Marshmallows-Prefix.pch create mode 100644 Marshmallows/Marshmallows.h create mode 100644 Marshmallows/NSDate+relative.h create mode 100644 Marshmallows/NSDate+relative.m create mode 100644 Marshmallows/NSString+sanity.h create mode 100644 Marshmallows/NSString+sanity.m diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9bce6af --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +xcuserdata diff --git a/Marshmallows.xcodeproj/project.pbxproj b/Marshmallows.xcodeproj/project.pbxproj new file mode 100644 index 0000000..4ab6030 --- /dev/null +++ b/Marshmallows.xcodeproj/project.pbxproj @@ -0,0 +1,278 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7BD1009D1413375B00A9921B /* RegexKitLite.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BD1009B1413375B00A9921B /* RegexKitLite.h */; }; + 7BD1009E1413375B00A9921B /* RegexKitLite.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BD1009C1413375B00A9921B /* RegexKitLite.m */; }; + 7BD100A2141341EB00A9921B /* MMHTTPClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BD100A0141341EB00A9921B /* MMHTTPClient.h */; }; + 7BD100A3141341EB00A9921B /* MMHTTPClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BD100A1141341EB00A9921B /* MMHTTPClient.m */; }; + 7BD100A614134FBE00A9921B /* MMHTTPRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BD100A414134FBE00A9921B /* MMHTTPRequest.h */; }; + 7BD100A714134FBE00A9921B /* MMHTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BD100A514134FBE00A9921B /* MMHTTPRequest.m */; }; + 7BD100AA141353B700A9921B /* NSDate+relative.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BD100A8141353B700A9921B /* NSDate+relative.h */; }; + 7BD100AB141353B700A9921B /* NSDate+relative.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BD100A9141353B700A9921B /* NSDate+relative.m */; }; + 7BE32D0A14132EE4008F2DEA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7BE32D0914132EE4008F2DEA /* Foundation.framework */; }; + 7BE32D6A14133618008F2DEA /* NSString+sanity.h in Headers */ = {isa = PBXBuildFile; fileRef = 7BE32D6814133618008F2DEA /* NSString+sanity.h */; }; + 7BE32D6B14133618008F2DEA /* NSString+sanity.m in Sources */ = {isa = PBXBuildFile; fileRef = 7BE32D6914133618008F2DEA /* NSString+sanity.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 7BD1009B1413375B00A9921B /* RegexKitLite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegexKitLite.h; sourceTree = ""; }; + 7BD1009C1413375B00A9921B /* RegexKitLite.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RegexKitLite.m; sourceTree = ""; }; + 7BD100A0141341EB00A9921B /* MMHTTPClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMHTTPClient.h; sourceTree = ""; }; + 7BD100A1141341EB00A9921B /* MMHTTPClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMHTTPClient.m; sourceTree = ""; }; + 7BD100A414134FBE00A9921B /* MMHTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMHTTPRequest.h; sourceTree = ""; }; + 7BD100A514134FBE00A9921B /* MMHTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMHTTPRequest.m; sourceTree = ""; }; + 7BD100A8141353B700A9921B /* NSDate+relative.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+relative.h"; sourceTree = ""; }; + 7BD100A9141353B700A9921B /* NSDate+relative.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+relative.m"; sourceTree = ""; }; + 7BE32D0614132EE4008F2DEA /* libMarshmallows.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMarshmallows.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 7BE32D0914132EE4008F2DEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 7BE32D0D14132EE4008F2DEA /* Marshmallows-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Marshmallows-Prefix.pch"; sourceTree = ""; }; + 7BE32D0E14132EE4008F2DEA /* Marshmallows.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Marshmallows.h; sourceTree = ""; }; + 7BE32D6814133618008F2DEA /* NSString+sanity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+sanity.h"; sourceTree = ""; }; + 7BE32D6914133618008F2DEA /* NSString+sanity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+sanity.m"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 7BE32D0314132EE4008F2DEA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 7BE32D0A14132EE4008F2DEA /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 7BD1009F1413396F00A9921B /* RegexKitLite */ = { + isa = PBXGroup; + children = ( + 7BD1009B1413375B00A9921B /* RegexKitLite.h */, + 7BD1009C1413375B00A9921B /* RegexKitLite.m */, + ); + name = RegexKitLite; + sourceTree = ""; + }; + 7BE32CFB14132EE3008F2DEA = { + isa = PBXGroup; + children = ( + 7BE32D0B14132EE4008F2DEA /* Marshmallows */, + 7BD1009F1413396F00A9921B /* RegexKitLite */, + 7BE32D0814132EE4008F2DEA /* Frameworks */, + 7BE32D0714132EE4008F2DEA /* Products */, + ); + sourceTree = ""; + }; + 7BE32D0714132EE4008F2DEA /* Products */ = { + isa = PBXGroup; + children = ( + 7BE32D0614132EE4008F2DEA /* libMarshmallows.a */, + ); + name = Products; + sourceTree = ""; + }; + 7BE32D0814132EE4008F2DEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 7BE32D0914132EE4008F2DEA /* Foundation.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 7BE32D0B14132EE4008F2DEA /* Marshmallows */ = { + isa = PBXGroup; + children = ( + 7BE32D0E14132EE4008F2DEA /* Marshmallows.h */, + 7BD100A0141341EB00A9921B /* MMHTTPClient.h */, + 7BD100A1141341EB00A9921B /* MMHTTPClient.m */, + 7BD100A414134FBE00A9921B /* MMHTTPRequest.h */, + 7BD100A514134FBE00A9921B /* MMHTTPRequest.m */, + 7BD100A8141353B700A9921B /* NSDate+relative.h */, + 7BD100A9141353B700A9921B /* NSDate+relative.m */, + 7BE32D6814133618008F2DEA /* NSString+sanity.h */, + 7BE32D6914133618008F2DEA /* NSString+sanity.m */, + 7BE32D0C14132EE4008F2DEA /* Supporting Files */, + ); + path = Marshmallows; + sourceTree = ""; + }; + 7BE32D0C14132EE4008F2DEA /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 7BE32D0D14132EE4008F2DEA /* Marshmallows-Prefix.pch */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 7BE32D0414132EE4008F2DEA /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 7BE32D6A14133618008F2DEA /* NSString+sanity.h in Headers */, + 7BD1009D1413375B00A9921B /* RegexKitLite.h in Headers */, + 7BD100A2141341EB00A9921B /* MMHTTPClient.h in Headers */, + 7BD100A614134FBE00A9921B /* MMHTTPRequest.h in Headers */, + 7BD100AA141353B700A9921B /* NSDate+relative.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 7BE32D0514132EE4008F2DEA /* Marshmallows */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7BE32D1314132EE4008F2DEA /* Build configuration list for PBXNativeTarget "Marshmallows" */; + buildPhases = ( + 7BE32D0214132EE4008F2DEA /* Sources */, + 7BE32D0314132EE4008F2DEA /* Frameworks */, + 7BE32D0414132EE4008F2DEA /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Marshmallows; + productName = Marshmallows; + productReference = 7BE32D0614132EE4008F2DEA /* libMarshmallows.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 7BE32CFD14132EE3008F2DEA /* Project object */ = { + isa = PBXProject; + attributes = { + ORGANIZATIONNAME = "Guru Logic"; + }; + buildConfigurationList = 7BE32D0014132EE3008F2DEA /* Build configuration list for PBXProject "Marshmallows" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 7BE32CFB14132EE3008F2DEA; + productRefGroup = 7BE32D0714132EE4008F2DEA /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 7BE32D0514132EE4008F2DEA /* Marshmallows */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 7BE32D0214132EE4008F2DEA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7BE32D6B14133618008F2DEA /* NSString+sanity.m in Sources */, + 7BD1009E1413375B00A9921B /* RegexKitLite.m in Sources */, + 7BD100A3141341EB00A9921B /* MMHTTPClient.m in Sources */, + 7BD100A714134FBE00A9921B /* MMHTTPRequest.m in Sources */, + 7BD100AB141353B700A9921B /* NSDate+relative.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 7BE32D1114132EE4008F2DEA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + COPY_PHASE_STRIP = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_VERSION = com.apple.compilers.llvmgcc42; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 4.3; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 7BE32D1214132EE4008F2DEA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + COPY_PHASE_STRIP = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_VERSION = com.apple.compilers.llvmgcc42; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 4.3; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 7BE32D1414132EE4008F2DEA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DSTROOT = /tmp/Marshmallows.dst; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Marshmallows/Marshmallows-Prefix.pch"; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 7BE32D1514132EE4008F2DEA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DSTROOT = /tmp/Marshmallows.dst; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "Marshmallows/Marshmallows-Prefix.pch"; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 7BE32D0014132EE3008F2DEA /* Build configuration list for PBXProject "Marshmallows" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7BE32D1114132EE4008F2DEA /* Debug */, + 7BE32D1214132EE4008F2DEA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7BE32D1314132EE4008F2DEA /* Build configuration list for PBXNativeTarget "Marshmallows" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7BE32D1414132EE4008F2DEA /* Debug */, + 7BE32D1514132EE4008F2DEA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 7BE32CFD14132EE3008F2DEA /* Project object */; +} diff --git a/Marshmallows.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Marshmallows.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..b58da1c --- /dev/null +++ b/Marshmallows.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Marshmallows/MMHTTPClient.h b/Marshmallows/MMHTTPClient.h new file mode 100644 index 0000000..bee7446 --- /dev/null +++ b/Marshmallows/MMHTTPClient.h @@ -0,0 +1,64 @@ +// +// MMHTTPClient.h +// Marshmallows +// +// Created by Sami Samhuri on 11-09-03. +// Copyright 2011 Guru Logic. All rights reserved. +// + +#import + +#define MMHTTPClientStatusError -1 +#define MMHTTPClientDefaultTimeout 120 + +typedef void (^MMHTTPClientCallback)(NSInteger status, id data); +typedef void (^MMHTTPClientTextCallback)(NSInteger status, NSString *text); +typedef void (^MMHTTPClientImageCallback)(NSInteger status, UIImage *image); + +@interface MMHTTPClient : NSObject +{ + NSMutableDictionary *_callbacks; + NSMutableDictionary *_connections; + NSMutableDictionary *_data; + NSMutableDictionary *_headers; + NSMutableDictionary *_statusCodes; + NSMutableDictionary *_types; + NSString *_baseURL; + NSUInteger _timeout; +} + ++ (MMHTTPClient *) sharedClient; ++ (id) client; ++ (id) clientWithBaseURL: (NSString *)baseURL; ++ (id) clientWithBaseURL: (NSString *)baseURL timeout: (NSUInteger)timeout; + ++ (NSString *) pathFor: (NSString *)first, ... NS_REQUIRES_NIL_TERMINATION; ++ (NSString *) urlFor: (NSString *)first, ... NS_REQUIRES_NIL_TERMINATION; ++ (NSString *) urlWithPath: (NSString *)path; ++ (void) request: (NSDictionary *)options then: (MMHTTPClientCallback)callback; ++ (void) get: (NSString *)url then: (MMHTTPClientCallback)callback; ++ (void) getImage: (NSString *)url then: (MMHTTPClientImageCallback)callback; ++ (void) getText: (NSString *)url then: (MMHTTPClientTextCallback)callback; ++ (void) post: (NSString *)url then: (MMHTTPClientCallback)callback; ++ (void) post: (NSString *)url data: (NSData *)data then: (MMHTTPClientCallback)callback; ++ (void) put: (NSString *)url data: (NSData *)data then: (MMHTTPClientCallback)callback; ++ (void) delete: (NSString *)url then: (MMHTTPClientCallback)callback; + +@property (nonatomic, retain) NSString *baseURL; +@property NSUInteger timeout; + +- (id) initWithBaseURL: (NSString *)baseURl; +- (id) initWithBaseURL: (NSString *)baseURl timeout: (NSUInteger)timeout; +- (NSString *) pathFor: (NSString *)first, ... NS_REQUIRES_NIL_TERMINATION; +- (NSString *) urlFor: (NSString *)first, ... NS_REQUIRES_NIL_TERMINATION; +- (NSString *) urlWithPath: (NSString *)path; +- (void) request: (NSDictionary *)options then: (MMHTTPClientCallback)callback; +- (void) get: (NSString *)url then: (MMHTTPClientCallback)callback; +- (void) getImage: (NSString *)url then: (MMHTTPClientImageCallback)callback; +- (void) getText: (NSString *)url then: (MMHTTPClientTextCallback)callback; +- (void) post: (NSString *)url then: (MMHTTPClientCallback)callback; +- (void) post: (NSString *)url data: (NSData *)data then: (MMHTTPClientCallback)callback; +- (void) put: (NSString *)url data: (NSData *)data then: (MMHTTPClientCallback)callback; +- (void) delete: (NSString *)url then: (MMHTTPClientCallback)callback; + +@end diff --git a/Marshmallows/MMHTTPClient.m b/Marshmallows/MMHTTPClient.m new file mode 100644 index 0000000..498b404 --- /dev/null +++ b/Marshmallows/MMHTTPClient.m @@ -0,0 +1,355 @@ +// +// MMHTTPClient.m +// Marshmallows +// +// Created by Sami Samhuri on 11-09-03. +// Copyright 2011 Guru Logic. All rights reserved. +// + +#import "MMHTTPClient.h" +#import "NSString+sanity.h" + +MMHTTPClient *_client; + +NSString *JoinURLComponents(NSString *first, va_list args) +{ + NSMutableString *url = [NSMutableString string]; + NSString *slash = @""; + for (NSString *arg = first; arg != nil; arg = va_arg(args, NSString *)) { + [url appendFormat: @"%@%@", slash, [arg stringByURLEncoding]]; + slash = @"/"; + } + return [NSString stringWithString: url]; +} + +@implementation MMHTTPClient + +@synthesize baseURL = _baseURL; +@synthesize timeout = _timeout; + ++ (MMHTTPClient *) sharedClient +{ + if (!_client) { + _client = [[self alloc] init]; + } + return _client; +} + ++ (id) client +{ + return [[[self alloc] init] autorelease]; +} + ++ (id) clientWithBaseURL: (NSString *)baseURL +{ + return [[[self alloc] initWithBaseURL: baseURL] autorelease]; +} + ++ (id) clientWithBaseURL: (NSString *)baseURL timeout: (NSUInteger)timeout +{ + return [[[self alloc] initWithBaseURL: baseURL timeout: timeout] autorelease]; +} + ++ (NSString *) pathFor: (NSString *)first, ... +{ + va_list args; + va_start(args, first); + NSString *url = JoinURLComponents(first, args); + va_end(args); + return url; +} + ++ (NSString *) urlFor: (NSString *)first, ... +{ + va_list args; + va_start(args, first); + NSString *url = [[[self sharedClient] baseURL] stringByAppendingString: JoinURLComponents(first, args)]; + va_end(args); + return url; +} + ++ (NSString *) urlWithPath: (NSString *)path +{ + return [[[self sharedClient] baseURL] stringByAppendingPathComponent: path]; +} + ++ (void) request: (NSDictionary *)options then: (MMHTTPClientCallback)callback +{ + [[self sharedClient] request: options then: callback]; +} + ++ (void) get: (NSString *)url then: (MMHTTPClientCallback)callback +{ + [[self sharedClient] get: url then: callback]; +} + ++ (void) getImage: (NSString *)url then: (MMHTTPClientImageCallback)callback +{ + [[self sharedClient] getImage: url then: callback]; +} + ++ (void) getText: (NSString *)url then: (MMHTTPClientTextCallback)callback +{ + [[self sharedClient] getText: url then: callback]; +} + ++ (void) post: (NSString *)url then: (MMHTTPClientCallback)callback +{ + [[self sharedClient] post: url then: callback]; +} + ++ (void) post: (NSString *)url data: (NSData *)data then: (MMHTTPClientCallback)callback +{ + [[self sharedClient] post: url data: data then: callback]; +} + ++ (void) put: (NSString *)url data: (NSData *)data then: (MMHTTPClientCallback)callback +{ + [[self sharedClient] put: url data: data then: callback]; +} + ++ (void) delete: (NSString *)url then: (MMHTTPClientCallback)callback +{ + [[self sharedClient] delete: url then: callback]; +} + +- (id) init +{ + return [self initWithBaseURL: nil timeout: MMHTTPClientDefaultTimeout]; +} + +- (id) initWithBaseURL: (NSString *)baseURL +{ + return [self initWithBaseURL: baseURL timeout: MMHTTPClientDefaultTimeout]; +} + +- (id) initWithBaseURL: (NSString *)baseURL timeout: (NSUInteger)timeout +{ + self = [super init]; + if (self) { + _baseURL = [baseURL copy]; + _timeout = timeout; + _callbacks = [[NSMutableDictionary alloc] init]; + _connections = [[NSMutableDictionary alloc] init]; + _data = [[NSMutableDictionary alloc] init]; + _headers = [[NSMutableDictionary alloc] init]; + _statusCodes = [[NSMutableDictionary alloc] init]; + _types = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (NSString *) pathFor: (NSString *)first, ... +{ + va_list args; + va_start(args, first); + NSString *url = JoinURLComponents(first, args); + va_end(args); + return url; +} + +- (NSString *) urlFor: (NSString *)first, ... +{ + va_list args; + va_start(args, first); + NSString *url = [_baseURL stringByAppendingString: JoinURLComponents(first, args)]; + va_end(args); + return url; +} + +- (NSString *) urlWithPath: (NSString *)path +{ + return [_baseURL stringByAppendingPathComponent: path]; +} + +- (void) getImage: (NSString *)url then: (MMHTTPClientImageCallback)callback +{ + [self request: [NSDictionary dictionary] then: (MMHTTPClientCallback)callback]; +} + +- (void) getText: (NSString *)url then: (MMHTTPClientTextCallback)callback +{ + NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: + url, @"url", + @"text", @"type", + nil]; + [self request: options then: (MMHTTPClientCallback)callback]; +} + +- (void) get: (NSString *)url then: (MMHTTPClientCallback)callback +{ + NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: + url, @"url", + @"image", @"type", + nil]; + [self request: options then: (MMHTTPClientCallback)callback]; +} + +- (void) post: (NSString *)url then: (MMHTTPClientCallback)callback +{ + NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: + @"POST", @"method", + url, @"url", + nil]; + [self request: options then: callback]; +} + +- (void) post: (NSString *)url data: (NSData *)data then: (MMHTTPClientCallback)callback +{ + NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: + @"POST", @"method", + url, @"url", + data, @"data", + nil]; + [self request: options then: callback]; +} + +- (void) put: (NSString *)url data: (NSData *)data then: (MMHTTPClientCallback)callback +{ + NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: + @"PUT", @"method", + url, @"url", + data, @"data", + nil]; + [self request: options then: callback]; +} + +- (void) delete: (NSString *)url then: (MMHTTPClientCallback)callback +{ + NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: + @"DELETE", @"method", + url, @"url", + nil]; + [self request: options then: callback]; +} + +- (void) request: (NSDictionary *)options then: (MMHTTPClientCallback)callback +{ + NSString *urlString = [options valueForKey: @"url"]; + NSString *method = [options valueForKey: @"method"]; + NSData *data = [options valueForKey: @"data"]; + NSDictionary *headers = [options valueForKey: @"headers"]; + NSString *type = [options valueForKey: @"type"]; + + if (!method) method = @"GET"; + + if (![[urlString substringToIndex: 5] isEqualToString: @"http:"] + && ![[urlString substringToIndex: 6] isEqualToString: @"https:"]) + { + urlString = [self urlWithPath: urlString]; + } + NSURL *url = [NSURL URLWithString: urlString]; + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: url + cachePolicy: NSURLRequestUseProtocolCachePolicy + timeoutInterval: self.timeout]; + [request setHTTPMethod: method]; + + if (data && ([method isEqualToString: @"POST"] || [method isEqualToString: @"PUT"])) { + [request setHTTPBody: data]; + } + + if (headers) { + for (NSString *key in headers) { + [request setValue: [headers objectForKey: key] forHTTPHeaderField: key]; + } + } + + NSURLConnection *connection = [NSURLConnection connectionWithRequest: request delegate: self]; + NSString *key = [connection description]; + [_callbacks setObject: [[callback copy] autorelease] forKey: [connection description]]; + [_connections setObject: connection forKey: key]; + if (type) [_types setObject: type forKey: key]; +} + + +#pragma mark - NSURLConnection delegate methods + +- (void) connection: (NSURLConnection *)connection didReceiveResponse: (NSURLResponse *)response +{ + NSString *key = [connection description]; + NSNumber *status; + NSDictionary *headers; + + if ([response respondsToSelector :@selector(statusCode)]) + { + status = [NSNumber numberWithInt: [(NSHTTPURLResponse *)response statusCode]]; + headers = [(NSHTTPURLResponse *)response allHeaderFields]; + } + else { + NSLog(@"Not an HTTP response? connection: %@ response: %@", connection, response); + status = [NSNumber numberWithInt: 500]; + headers = [NSDictionary dictionary]; + } + + [_statusCodes setObject: status forKey: key]; + [_headers setObject: headers forKey: key]; + [_data setObject: [[[NSMutableData alloc] init] autorelease] forKey: key]; +} + +- (void) connection: (NSURLConnection *)connection didReceiveData: (NSData *)data +{ + [[_data objectForKey: [connection description]] appendData: data]; +} + +- (void) connection: (NSURLConnection *)connection didFailWithError: (NSError *)error +{ + NSString *key = [connection description]; + MMHTTPClientCallback callback = [_callbacks objectForKey: key]; + + callback(MMHTTPClientStatusError, nil); + + [_statusCodes removeObjectForKey: key]; + [_callbacks removeObjectForKey: key]; + [_data removeObjectForKey: key]; +} + +- (void) connectionDidFinishLoading: (NSURLConnection *)connection +{ + NSString *key = [connection description]; + MMHTTPClientCallback callback = [_callbacks objectForKey: key]; + int status = [[_statusCodes objectForKey: key] intValue]; + NSString *type = [_types objectForKey: key]; + id data = nil; + if (status == 200) { + if ([type isEqualToString: @"text"]) { + NSData *rawData = [_data objectForKey: key]; + data = [[[NSString alloc] initWithBytes: rawData.bytes + length: rawData.length + encoding: NSUTF8StringEncoding] autorelease]; + } + else if ([type isEqualToString: @"image"]) { + data = [UIImage imageWithData: [_data objectForKey: key]]; + } + else { + data = [_data objectForKey: key]; + } + } + + callback(status, data); + + [_callbacks removeObjectForKey: key]; + [_connections removeObjectForKey: key]; + [_data removeObjectForKey: key]; + [_headers removeObjectForKey: key]; + [_statusCodes removeObjectForKey: key]; + [_types removeObjectForKey: key]; +} + +- (void) dealloc +{ + for (NSURLConnection *conn in _connections) { + [conn cancel]; + } + + [_baseURL release]; + [_callbacks release]; + [_connections release]; + [_data release]; + [_headers release]; + [_statusCodes release]; + [_types release]; + [super dealloc]; +} + +@end diff --git a/Marshmallows/Marshmallows-Prefix.pch b/Marshmallows/Marshmallows-Prefix.pch new file mode 100644 index 0000000..a44101c --- /dev/null +++ b/Marshmallows/Marshmallows-Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'Marshmallows' target in the 'Marshmallows' project +// + +#ifdef __OBJC__ + #import +#endif diff --git a/Marshmallows/Marshmallows.h b/Marshmallows/Marshmallows.h new file mode 100644 index 0000000..d7a75ba --- /dev/null +++ b/Marshmallows/Marshmallows.h @@ -0,0 +1,12 @@ +// +// Marshmallows.h +// Marshmallows +// +// Created by Sami Samhuri on 11-09-03. +// Copyright 2011 Guru Logic. All rights reserved. +// + +#import + +#import "NSDate+relative.h" +#import "NSString+sanity.h" diff --git a/Marshmallows/NSDate+relative.h b/Marshmallows/NSDate+relative.h new file mode 100644 index 0000000..7d4322d --- /dev/null +++ b/Marshmallows/NSDate+relative.h @@ -0,0 +1,16 @@ +// +// NSDate+relative.h +// UberClassifieds +// +// Created by Sami Samhuri on 11-06-18. +// Copyright 2011 Betastreet Media. All rights reserved. +// + +#import + + +@interface NSDate (NSDate_relative) + +- (NSString *) relativeToNow; + +@end diff --git a/Marshmallows/NSDate+relative.m b/Marshmallows/NSDate+relative.m new file mode 100644 index 0000000..c6da255 --- /dev/null +++ b/Marshmallows/NSDate+relative.m @@ -0,0 +1,60 @@ +// +// NSDate+relative.m +// UberClassifieds +// +// Created by Sami Samhuri on 11-06-18. +// Copyright 2011 Betastreet Media. All rights reserved. +// + +#import "NSDate+relative.h" + +#define MINUTE 60.0 +#define HOUR (60.0 * MINUTE) +#define DAY (24.0 * HOUR) +#define WEEK (7.0 * DAY) +#define MONTH (30.0 * DAY) + +@implementation NSDate (NSDate_relative) + +- (NSString *) relativeToNow +{ + double diff = [[NSDate date] timeIntervalSinceDate: self]; + if (diff < MINUTE) { + return @"right now"; + } + else if (diff < 2 * MINUTE) { + return @"a minute ago"; + } + else if (diff < HOUR) { + return [NSString stringWithFormat: @"%d minutes ago", (int)(diff / MINUTE)]; + } + else if (diff < 2 * HOUR) { + return @"an hour ago"; + } + else if (diff < DAY) { + return [NSString stringWithFormat: @"%d hours ago", (int)(diff / HOUR)]; + } + else if (diff < 2 * DAY) { + return @"yesterday"; + } + else if (diff < WEEK) { + return [NSString stringWithFormat: @"%d days ago", (int)(diff / DAY)]; + } + else if (diff < 2 * WEEK) { + return @"last week"; + } + else if (diff < 4 * WEEK) { + return [NSString stringWithFormat: @"%d weeks ago", (int)(diff / WEEK)]; + } + else if (diff < 8 * WEEK) { + return @"last month"; + } + else if (diff < 12 * MONTH) { + return [NSString stringWithFormat: @"%d months ago", (int)(diff / MONTH)]; + } + else { + return @"a long time ago"; + } +} + +@end diff --git a/Marshmallows/NSString+sanity.h b/Marshmallows/NSString+sanity.h new file mode 100644 index 0000000..ac5b841 --- /dev/null +++ b/Marshmallows/NSString+sanity.h @@ -0,0 +1,19 @@ +// +// NSString+sanity.h +// Marshmallows +// +// Created by Sami Samhuri on 11-09-03. +// Copyright 2011 Guru Logic. All rights reserved. +// + +#import + +@interface NSString (NSString_sanity) + +- (NSString *) firstMatch: (NSString *)pattern; +- (NSString *) stringByReplacing: (NSString *)pattern with: (NSString *)replacement; +- (NSString *) stringByReplacingFirst: (NSString *)pattern with: (NSString *)replacement; +- (NSString *) stringByTrimmingWhitespace; +- (NSString *) stringByURLEncoding; + +@end diff --git a/Marshmallows/NSString+sanity.m b/Marshmallows/NSString+sanity.m new file mode 100644 index 0000000..415ebad --- /dev/null +++ b/Marshmallows/NSString+sanity.m @@ -0,0 +1,76 @@ +// +// NSString+sanity.m +// Marshmallows +// +// Created by Sami Samhuri on 11-09-03. +// Copyright 2011 Guru Logic. All rights reserved. +// + +#import "NSString+sanity.h" + +// Encode a string to embed in an URL. +NSString* URLEncode(NSString *string) { + return (NSString *) + CFURLCreateStringByAddingPercentEscapes(NULL, + (CFStringRef) string, + NULL, + (CFStringRef) @"!*'();:@&=+$,/?%#[]", + kCFStringEncodingUTF8); +} + + +@implementation NSString (NSString_sanity) + +- (NSString *) stringByTrimmingWhitespace +{ + return [self stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]]; +} + +- (NSString *) firstMatch: (NSString *)pattern +{ + NSRegularExpression *regex = [NSRegularExpression + regularExpressionWithPattern: pattern + options: 0 + error: NULL]; + NSRange match = [regex rangeOfFirstMatchInString: self + options: NSMatchingCompleted + range: NSMakeRange(0, self.length)]; + return match.location == NSNotFound ? nil : [self substringWithRange: match]; +} + +- (NSString *) stringByReplacing: (NSString *)pattern with: (NSString *)replacement +{ + NSRegularExpression *regex = [NSRegularExpression + regularExpressionWithPattern: pattern + options: NSRegularExpressionCaseInsensitive + error: NULL]; + return [regex stringByReplacingMatchesInString: self + options: NSMatchingCompleted + range: NSMakeRange(0, [self length]) + withTemplate: @""]; +} + +- (NSString *) stringByReplacingFirst: (NSString *)pattern with: (NSString *)replacement +{ + NSRegularExpression *regex = [NSRegularExpression + regularExpressionWithPattern: pattern + options: 0 + error: NULL]; + NSRange match = [regex rangeOfFirstMatchInString: self + options: NSMatchingCompleted + range: NSMakeRange(0, self.length)]; + if (match.location != NSNotFound) { + NSString *rest = [self substringFromIndex: match.location + match.length]; + return [[[self substringToIndex: match.location] + stringByAppendingString: replacement] + stringByAppendingString: rest]; + } + return [[self copy] autorelease]; +} + +- (NSString *) stringByURLEncoding +{ + return URLEncode(self); +} + +@end