├── .gitignore ├── .gitmodules ├── .travis.yml ├── AUTHORS ├── Example ├── AppDelegate.h ├── AppDelegate.m ├── Default-568h@2x.png ├── Raven-Info.plist ├── Raven-Prefix.pch ├── ViewController.h ├── ViewController.m ├── en.lproj │ ├── InfoPlist.strings │ └── MainStoryboard.storyboard └── main.m ├── LICENSE ├── README.md ├── Raven.podspec ├── Raven.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ ├── Raven (iOS).xcscheme │ └── RavenTests.xcscheme ├── Raven ├── Info.plist ├── Raven.h ├── RavenClient.h ├── RavenClient.m ├── RavenClient_Private.h ├── RavenConfig.h └── RavenConfig.m ├── RavenTests ├── RavenClientTest.h ├── RavenClientTest.m ├── RavenConfigTest.h ├── RavenConfigTest.m ├── RavenTests-Info.plist └── en.lproj │ └── InfoPlist.strings ├── bin └── test └── docs ├── Makefile ├── conf.py ├── index.rst ├── make.bat └── sentry-doc-config.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | build/* 3 | *.pbxuser 4 | !default.pbxuser 5 | *.mode1v3 6 | !default.mode1v3 7 | *.mode2v3 8 | !default.mode2v3 9 | *.perspectivev3 10 | !default.perspectivev3 11 | *.xcworkspace 12 | !default.xcworkspace 13 | xcuserdata 14 | profile 15 | *.moved-aside 16 | .DS_Store 17 | .idea 18 | docs/_build 19 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "docs/_sentryext"] 2 | path = docs/_sentryext 3 | url = https://github.com/getsentry/sentry-doc-support 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode7.1 3 | xcode_project: Raven.xcodeproj 4 | xcode_scheme: RavenTests 5 | xcode_target: RavenTests 6 | xcode_sdk: iphonesimulator 7 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Primary authors 2 | David Cramer - https://github.com/dcramer 3 | 4 | Contributors 5 | Kevin Renskers - https://github.com/kevinrenskers 6 | Kristian Glass - https://github.com/doismellburning 7 | Arthur Darcet- https://github.com/arthurdarcet 8 | lesterkp - https://github.com/lesterkp 9 | Christoph Lupprich - https://github.com/clupprich 10 | Dmitry Vorobyov - https://github.com/dvor 11 | Mark Anderson - https://github.com/manderson-productions -------------------------------------------------------------------------------- /Example/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // Raven 4 | // 5 | // Created by Kevin Renskers on 25-05-12. 6 | // Copyright (c) 2012 Gangverk. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Example/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // Raven 4 | // 5 | // Created by Kevin Renskers on 25-05-12. 6 | // Copyright (c) 2012 Gangverk. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "RavenClient.h" 11 | 12 | @implementation AppDelegate 13 | 14 | @synthesize window = _window; 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 17 | RavenClient *client = [RavenClient clientWithDSN:@"https://663998f40e734ea59087883feda37647:306481b9f6bb4a6287b334178d9f8c71@app.getsentry.com/4394"]; 18 | [RavenClient setSharedClient:client]; 19 | [[RavenClient sharedClient] setupExceptionHandler]; 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Example/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getsentry/raven-objc/f40485ba20ad82ec8370f112f0a17a0a9d73545f/Example/Default-568h@2x.png -------------------------------------------------------------------------------- /Example/Raven-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | Raven 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 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.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | MainStoryboard 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Example/Raven-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'Raven' target in the 'Raven' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_5_0 8 | #warning "This project uses features only available in iOS SDK 5.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /Example/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // Raven 4 | // 5 | // Created by Kevin Renskers on 25-05-12. 6 | // Copyright (c) 2012 Gangverk. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | @property (weak, nonatomic) IBOutlet UITableView *tableView; 14 | 15 | - (void)addStatus:(NSString *)status; 16 | - (IBAction)sendMessage; 17 | - (IBAction)generateException; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Example/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // Raven 4 | // 5 | // Created by Kevin Renskers on 25-05-12. 6 | // Copyright (c) 2012 Gangverk. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "RavenClient.h" 11 | 12 | 13 | @interface ViewController () 14 | @property (strong, nonatomic) NSMutableArray *status; 15 | @end 16 | 17 | 18 | @implementation ViewController 19 | 20 | @synthesize tableView = _tableView; 21 | @synthesize status = _status; 22 | 23 | #pragma mark - View lifecycle 24 | 25 | - (void)viewDidLoad { 26 | [super viewDidLoad]; 27 | self.status = [NSMutableArray array]; 28 | NSLog(@"RavenClient: %@", [RavenClient sharedClient]); 29 | } 30 | 31 | - (void)viewDidUnload { 32 | [self setTableView:nil]; 33 | [super viewDidUnload]; 34 | } 35 | 36 | #pragma mark - Public methods 37 | 38 | - (void)addStatus:(NSString *)status { 39 | [self.status addObject:status]; 40 | [self.tableView reloadData]; 41 | } 42 | 43 | - (IBAction)sendMessage { 44 | [self addStatus:@"Sending message..."]; 45 | RavenCaptureMessage(@"TEST %i %@ %f", 1, @"2", 3.0); 46 | } 47 | 48 | - (IBAction)generateException { 49 | [self addStatus:@"Generating exception..."]; 50 | [self performSelector:@selector(nonExistingSelector)]; 51 | } 52 | 53 | - (IBAction)sendError { 54 | NSError *error; 55 | RavenCaptureError(error); 56 | } 57 | 58 | - (IBAction)sendException { 59 | NSException *exception; 60 | RavenCaptureException(exception); 61 | } 62 | 63 | #pragma mark - UITableViewDelegate 64 | // Nothing... 65 | 66 | #pragma mark - UITableViewDataSource 67 | 68 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 69 | return [self.status count]; 70 | } 71 | 72 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 73 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"StatusCell"]; 74 | cell.textLabel.text = [self.status objectAtIndex:indexPath.row]; 75 | return cell; 76 | } 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /Example/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/en.lproj/MainStoryboard.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 28 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /Example/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Raven 4 | // 5 | // Created by Kevin Renskers on 25-05-12. 6 | // Copyright (c) 2012 Gangverk. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Kevin Renskers (http://mixedcase.nl/) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # *** DEPRECATED *** 3 | This SDK is deprecated. Use [sentry-cocoa](https://github.com/getsentry/sentry-cocoa). 4 | 5 | # raven-objc 6 | 7 | Objective-c client for [Sentry](https://www.getsentry.com/welcome/). 8 | 9 | ## Resources 10 | 11 | * [Documentation](https://docs.getsentry.com/hosted/clients/objc/) 12 | * [Download](https://cocoapods.org/pods/Raven) 13 | * [Issue tracker](https://github.com/getsentry/raven-objc/issues) 14 | * [![Join the chat at https://gitter.im/getsentry/raven-objc](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/getsentry/raven-objc?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 15 | * [![Build Status](https://travis-ci.org/getsentry/raven-objc.svg?branch=master)](https://travis-ci.org/getsentry/raven-objc) 16 | 17 | ## Contributing 18 | 19 | raven-objc is an open source project and your contribution is very much appreciated. 20 | 21 | 1. Check for [open issues](https://github.com/getsentry/raven-objc/issues) or [open a fresh issue](https://github.com/getsentry/raven-objc/issues/new) to start a discussion around a feature idea or a bug. 22 | 2. Fork the [repository on Github](https://github.com/getsentry/raven-objc) and make your changes. 23 | 3. Make sure to add yourself to AUTHORS and send a pull request. 24 | 25 | 26 | ## License 27 | 28 | raven-objc is available under the MIT license. See the LICENSE file for more info. 29 | -------------------------------------------------------------------------------- /Raven.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "Raven" 3 | s.version = "1.0.1" 4 | s.summary = "A client for Sentry (getsentry.com)." 5 | s.homepage = "https://getsentry.com/" 6 | s.license = { :type => 'MIT', :file => 'LICENSE' } 7 | s.author = { "David Cramer" => "dcramer@gmail.com" } 8 | s.source = { :git => "https://github.com/getsentry/raven-objc.git", :tag => s.version.to_s } 9 | s.source_files = ['Raven'] 10 | s.requires_arc = true 11 | s.documentation_url = 'https://docs.getsentry.com/hosted/clients/objc/' 12 | end 13 | -------------------------------------------------------------------------------- /Raven.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0A1479A316C2958F00D3B69D /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 0A1479A216C2958F00D3B69D /* Default-568h@2x.png */; }; 11 | 0A46FE9E156FA72300D97F26 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A46FE9D156FA72300D97F26 /* UIKit.framework */; }; 12 | 0A46FEA0156FA72300D97F26 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A46FE9F156FA72300D97F26 /* Foundation.framework */; }; 13 | 0A46FEA2156FA72300D97F26 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A46FEA1156FA72300D97F26 /* CoreGraphics.framework */; }; 14 | 0A46FEA8156FA72300D97F26 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0A46FEA6156FA72300D97F26 /* InfoPlist.strings */; }; 15 | 0A46FEAA156FA72300D97F26 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A46FEA9156FA72300D97F26 /* main.m */; }; 16 | 0A46FEAE156FA72300D97F26 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A46FEAD156FA72300D97F26 /* AppDelegate.m */; }; 17 | 0A46FEB1156FA72300D97F26 /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0A46FEAF156FA72300D97F26 /* MainStoryboard.storyboard */; }; 18 | 0A46FEB4156FA72300D97F26 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A46FEB3156FA72300D97F26 /* ViewController.m */; }; 19 | 0A46FEBD156FA72300D97F26 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A46FE9D156FA72300D97F26 /* UIKit.framework */; }; 20 | 0A46FEBE156FA72300D97F26 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0A46FE9F156FA72300D97F26 /* Foundation.framework */; }; 21 | 0A46FEC6156FA72300D97F26 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0A46FEC4156FA72300D97F26 /* InfoPlist.strings */; }; 22 | 0A46FEC9156FA72300D97F26 /* RavenClientTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A46FEC8156FA72300D97F26 /* RavenClientTest.m */; }; 23 | 0A46FEDA156FA8D900D97F26 /* RavenClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A46FED9156FA8D900D97F26 /* RavenClient.m */; }; 24 | 1DA6EDFE1A6E0A6C00F2510C /* Raven.h in Headers */ = {isa = PBXBuildFile; fileRef = 1DA6EDFD1A6E0A6C00F2510C /* Raven.h */; settings = {ATTRIBUTES = (Public, ); }; }; 25 | 1DA6EE121A6E0AD400F2510C /* RavenClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A46FED9156FA8D900D97F26 /* RavenClient.m */; }; 26 | 1DA6EE131A6E0AD600F2510C /* RavenConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BAEC13D168E6FC100408CDB /* RavenConfig.m */; }; 27 | 1DA6EE141A6E0ADB00F2510C /* RavenConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 8BAEC13C168E6FC100408CDB /* RavenConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; 28 | 1DA6EE151A6E0ADE00F2510C /* RavenClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 0A46FED8156FA8D900D97F26 /* RavenClient.h */; settings = {ATTRIBUTES = (Public, ); }; }; 29 | 1DA6EE161A6E0AE000F2510C /* RavenClient_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 8BAEC123168E6D0200408CDB /* RavenClient_Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; 30 | 8BAEC13E168E6FC100408CDB /* RavenConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BAEC13D168E6FC100408CDB /* RavenConfig.m */; }; 31 | 8BAEC142168E725100408CDB /* RavenConfigTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BAEC141168E725100408CDB /* RavenConfigTest.m */; }; 32 | 8BAEC154168E747900408CDB /* RavenClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A46FED9156FA8D900D97F26 /* RavenClient.m */; }; 33 | 8BAEC156168E748700408CDB /* RavenConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BAEC13D168E6FC100408CDB /* RavenConfig.m */; }; 34 | /* End PBXBuildFile section */ 35 | 36 | /* Begin PBXFileReference section */ 37 | 0A1479A216C2958F00D3B69D /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 38 | 0A33DE37156FA9D500AB3299 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = text; path = README.md; sourceTree = ""; }; 39 | 0A33DE39156FAA0B00AB3299 /* AUTHORS */ = {isa = PBXFileReference; lastKnownFileType = text; path = AUTHORS; sourceTree = ""; }; 40 | 0A33DE3A156FAA0B00AB3299 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 41 | 0A46FE99156FA72300D97F26 /* RavenExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RavenExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | 0A46FE9D156FA72300D97F26 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 43 | 0A46FE9F156FA72300D97F26 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 44 | 0A46FEA1156FA72300D97F26 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 45 | 0A46FEA5156FA72300D97F26 /* Raven-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Raven-Info.plist"; sourceTree = ""; }; 46 | 0A46FEA7156FA72300D97F26 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 47 | 0A46FEA9156FA72300D97F26 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 48 | 0A46FEAB156FA72300D97F26 /* Raven-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Raven-Prefix.pch"; sourceTree = ""; }; 49 | 0A46FEAC156FA72300D97F26 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 50 | 0A46FEAD156FA72300D97F26 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 51 | 0A46FEB0156FA72300D97F26 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard.storyboard; sourceTree = ""; }; 52 | 0A46FEB2156FA72300D97F26 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 53 | 0A46FEB3156FA72300D97F26 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 54 | 0A46FEBA156FA72300D97F26 /* RavenTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RavenTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | 0A46FEC3156FA72300D97F26 /* RavenTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RavenTests-Info.plist"; sourceTree = ""; }; 56 | 0A46FEC5156FA72300D97F26 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 57 | 0A46FEC7156FA72300D97F26 /* RavenClientTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RavenClientTest.h; sourceTree = ""; }; 58 | 0A46FEC8156FA72300D97F26 /* RavenClientTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RavenClientTest.m; sourceTree = ""; }; 59 | 0A46FED8156FA8D900D97F26 /* RavenClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RavenClient.h; sourceTree = ""; }; 60 | 0A46FED9156FA8D900D97F26 /* RavenClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RavenClient.m; sourceTree = ""; }; 61 | 1DA6EDF91A6E0A6C00F2510C /* Raven.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Raven.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 62 | 1DA6EDFC1A6E0A6C00F2510C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 63 | 1DA6EDFD1A6E0A6C00F2510C /* Raven.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Raven.h; sourceTree = ""; }; 64 | 8BAEC123168E6D0200408CDB /* RavenClient_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RavenClient_Private.h; sourceTree = ""; }; 65 | 8BAEC13C168E6FC100408CDB /* RavenConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RavenConfig.h; sourceTree = ""; }; 66 | 8BAEC13D168E6FC100408CDB /* RavenConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RavenConfig.m; sourceTree = ""; }; 67 | 8BAEC140168E725100408CDB /* RavenConfigTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RavenConfigTest.h; sourceTree = ""; }; 68 | 8BAEC141168E725100408CDB /* RavenConfigTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RavenConfigTest.m; sourceTree = ""; }; 69 | /* End PBXFileReference section */ 70 | 71 | /* Begin PBXFrameworksBuildPhase section */ 72 | 0A46FE96156FA72300D97F26 /* Frameworks */ = { 73 | isa = PBXFrameworksBuildPhase; 74 | buildActionMask = 2147483647; 75 | files = ( 76 | 0A46FE9E156FA72300D97F26 /* UIKit.framework in Frameworks */, 77 | 0A46FEA0156FA72300D97F26 /* Foundation.framework in Frameworks */, 78 | 0A46FEA2156FA72300D97F26 /* CoreGraphics.framework in Frameworks */, 79 | ); 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | 0A46FEB6156FA72300D97F26 /* Frameworks */ = { 83 | isa = PBXFrameworksBuildPhase; 84 | buildActionMask = 2147483647; 85 | files = ( 86 | 0A46FEBD156FA72300D97F26 /* UIKit.framework in Frameworks */, 87 | 0A46FEBE156FA72300D97F26 /* Foundation.framework in Frameworks */, 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | 1DA6EDF51A6E0A6C00F2510C /* Frameworks */ = { 92 | isa = PBXFrameworksBuildPhase; 93 | buildActionMask = 2147483647; 94 | files = ( 95 | ); 96 | runOnlyForDeploymentPostprocessing = 0; 97 | }; 98 | /* End PBXFrameworksBuildPhase section */ 99 | 100 | /* Begin PBXGroup section */ 101 | 0A46FE8E156FA72300D97F26 = { 102 | isa = PBXGroup; 103 | children = ( 104 | 0A46FED2156FA74700D97F26 /* Raven */, 105 | 0A46FEA3156FA72300D97F26 /* Example */, 106 | 0A46FEC1156FA72300D97F26 /* RavenTests */, 107 | 0A46FE9C156FA72300D97F26 /* Frameworks */, 108 | 0A46FE9A156FA72300D97F26 /* Products */, 109 | 0A33DE39156FAA0B00AB3299 /* AUTHORS */, 110 | 0A33DE3A156FAA0B00AB3299 /* LICENSE */, 111 | 0A33DE37156FA9D500AB3299 /* README.md */, 112 | ); 113 | sourceTree = ""; 114 | }; 115 | 0A46FE9A156FA72300D97F26 /* Products */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | 0A46FE99156FA72300D97F26 /* RavenExample.app */, 119 | 0A46FEBA156FA72300D97F26 /* RavenTests.xctest */, 120 | 1DA6EDF91A6E0A6C00F2510C /* Raven.framework */, 121 | ); 122 | name = Products; 123 | sourceTree = ""; 124 | }; 125 | 0A46FE9C156FA72300D97F26 /* Frameworks */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 0A46FE9D156FA72300D97F26 /* UIKit.framework */, 129 | 0A46FE9F156FA72300D97F26 /* Foundation.framework */, 130 | 0A46FEA1156FA72300D97F26 /* CoreGraphics.framework */, 131 | ); 132 | name = Frameworks; 133 | sourceTree = ""; 134 | }; 135 | 0A46FEA3156FA72300D97F26 /* Example */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | 0A46FEAC156FA72300D97F26 /* AppDelegate.h */, 139 | 0A46FEAD156FA72300D97F26 /* AppDelegate.m */, 140 | 0A46FEAF156FA72300D97F26 /* MainStoryboard.storyboard */, 141 | 0A46FEB2156FA72300D97F26 /* ViewController.h */, 142 | 0A46FEB3156FA72300D97F26 /* ViewController.m */, 143 | 0A46FEA4156FA72300D97F26 /* Supporting Files */, 144 | ); 145 | path = Example; 146 | sourceTree = ""; 147 | }; 148 | 0A46FEA4156FA72300D97F26 /* Supporting Files */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 0A1479A216C2958F00D3B69D /* Default-568h@2x.png */, 152 | 0A46FEA5156FA72300D97F26 /* Raven-Info.plist */, 153 | 0A46FEA6156FA72300D97F26 /* InfoPlist.strings */, 154 | 0A46FEA9156FA72300D97F26 /* main.m */, 155 | 0A46FEAB156FA72300D97F26 /* Raven-Prefix.pch */, 156 | ); 157 | name = "Supporting Files"; 158 | sourceTree = ""; 159 | }; 160 | 0A46FEC1156FA72300D97F26 /* RavenTests */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | 0A46FEC7156FA72300D97F26 /* RavenClientTest.h */, 164 | 0A46FEC8156FA72300D97F26 /* RavenClientTest.m */, 165 | 0A46FEC2156FA72300D97F26 /* Supporting Files */, 166 | 8BAEC140168E725100408CDB /* RavenConfigTest.h */, 167 | 8BAEC141168E725100408CDB /* RavenConfigTest.m */, 168 | ); 169 | path = RavenTests; 170 | sourceTree = ""; 171 | }; 172 | 0A46FEC2156FA72300D97F26 /* Supporting Files */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | 0A46FEC3156FA72300D97F26 /* RavenTests-Info.plist */, 176 | 0A46FEC4156FA72300D97F26 /* InfoPlist.strings */, 177 | ); 178 | name = "Supporting Files"; 179 | sourceTree = ""; 180 | }; 181 | 0A46FED2156FA74700D97F26 /* Raven */ = { 182 | isa = PBXGroup; 183 | children = ( 184 | 1DA6EDFD1A6E0A6C00F2510C /* Raven.h */, 185 | 0A46FED8156FA8D900D97F26 /* RavenClient.h */, 186 | 0A46FED9156FA8D900D97F26 /* RavenClient.m */, 187 | 8BAEC123168E6D0200408CDB /* RavenClient_Private.h */, 188 | 8BAEC13C168E6FC100408CDB /* RavenConfig.h */, 189 | 8BAEC13D168E6FC100408CDB /* RavenConfig.m */, 190 | 1DA6EDFB1A6E0A6C00F2510C /* Supporting Files */, 191 | ); 192 | path = Raven; 193 | sourceTree = ""; 194 | }; 195 | 1DA6EDFB1A6E0A6C00F2510C /* Supporting Files */ = { 196 | isa = PBXGroup; 197 | children = ( 198 | 1DA6EDFC1A6E0A6C00F2510C /* Info.plist */, 199 | ); 200 | name = "Supporting Files"; 201 | sourceTree = ""; 202 | }; 203 | /* End PBXGroup section */ 204 | 205 | /* Begin PBXHeadersBuildPhase section */ 206 | 1DA6EDF61A6E0A6C00F2510C /* Headers */ = { 207 | isa = PBXHeadersBuildPhase; 208 | buildActionMask = 2147483647; 209 | files = ( 210 | 1DA6EDFE1A6E0A6C00F2510C /* Raven.h in Headers */, 211 | 1DA6EE141A6E0ADB00F2510C /* RavenConfig.h in Headers */, 212 | 1DA6EE151A6E0ADE00F2510C /* RavenClient.h in Headers */, 213 | 1DA6EE161A6E0AE000F2510C /* RavenClient_Private.h in Headers */, 214 | ); 215 | runOnlyForDeploymentPostprocessing = 0; 216 | }; 217 | /* End PBXHeadersBuildPhase section */ 218 | 219 | /* Begin PBXNativeTarget section */ 220 | 0A46FE98156FA72300D97F26 /* RavenExample */ = { 221 | isa = PBXNativeTarget; 222 | buildConfigurationList = 0A46FECC156FA72300D97F26 /* Build configuration list for PBXNativeTarget "RavenExample" */; 223 | buildPhases = ( 224 | 0A46FE95156FA72300D97F26 /* Sources */, 225 | 0A46FE96156FA72300D97F26 /* Frameworks */, 226 | 0A46FE97156FA72300D97F26 /* Resources */, 227 | ); 228 | buildRules = ( 229 | ); 230 | dependencies = ( 231 | ); 232 | name = RavenExample; 233 | productName = Raven; 234 | productReference = 0A46FE99156FA72300D97F26 /* RavenExample.app */; 235 | productType = "com.apple.product-type.application"; 236 | }; 237 | 0A46FEB9156FA72300D97F26 /* RavenTests */ = { 238 | isa = PBXNativeTarget; 239 | buildConfigurationList = 0A46FECF156FA72300D97F26 /* Build configuration list for PBXNativeTarget "RavenTests" */; 240 | buildPhases = ( 241 | 0A46FEB5156FA72300D97F26 /* Sources */, 242 | 0A46FEB6156FA72300D97F26 /* Frameworks */, 243 | 0A46FEB7156FA72300D97F26 /* Resources */, 244 | 0A46FEB8156FA72300D97F26 /* ShellScript */, 245 | ); 246 | buildRules = ( 247 | ); 248 | dependencies = ( 249 | ); 250 | name = RavenTests; 251 | productName = RavenTests; 252 | productReference = 0A46FEBA156FA72300D97F26 /* RavenTests.xctest */; 253 | productType = "com.apple.product-type.bundle.unit-test"; 254 | }; 255 | 1DA6EDF81A6E0A6C00F2510C /* Raven (iOS) */ = { 256 | isa = PBXNativeTarget; 257 | buildConfigurationList = 1DA6EE101A6E0A6C00F2510C /* Build configuration list for PBXNativeTarget "Raven (iOS)" */; 258 | buildPhases = ( 259 | 1DA6EDF41A6E0A6C00F2510C /* Sources */, 260 | 1DA6EDF51A6E0A6C00F2510C /* Frameworks */, 261 | 1DA6EDF61A6E0A6C00F2510C /* Headers */, 262 | 1DA6EDF71A6E0A6C00F2510C /* Resources */, 263 | ); 264 | buildRules = ( 265 | ); 266 | dependencies = ( 267 | ); 268 | name = "Raven (iOS)"; 269 | productName = Raven; 270 | productReference = 1DA6EDF91A6E0A6C00F2510C /* Raven.framework */; 271 | productType = "com.apple.product-type.framework"; 272 | }; 273 | /* End PBXNativeTarget section */ 274 | 275 | /* Begin PBXProject section */ 276 | 0A46FE90156FA72300D97F26 /* Project object */ = { 277 | isa = PBXProject; 278 | attributes = { 279 | LastTestingUpgradeCheck = 0710; 280 | LastUpgradeCheck = 0710; 281 | ORGANIZATIONNAME = Gangverk; 282 | TargetAttributes = { 283 | 1DA6EDF81A6E0A6C00F2510C = { 284 | CreatedOnToolsVersion = 6.2; 285 | }; 286 | }; 287 | }; 288 | buildConfigurationList = 0A46FE93156FA72300D97F26 /* Build configuration list for PBXProject "Raven" */; 289 | compatibilityVersion = "Xcode 3.2"; 290 | developmentRegion = English; 291 | hasScannedForEncodings = 0; 292 | knownRegions = ( 293 | en, 294 | ); 295 | mainGroup = 0A46FE8E156FA72300D97F26; 296 | productRefGroup = 0A46FE9A156FA72300D97F26 /* Products */; 297 | projectDirPath = ""; 298 | projectRoot = ""; 299 | targets = ( 300 | 1DA6EDF81A6E0A6C00F2510C /* Raven (iOS) */, 301 | 0A46FE98156FA72300D97F26 /* RavenExample */, 302 | 0A46FEB9156FA72300D97F26 /* RavenTests */, 303 | ); 304 | }; 305 | /* End PBXProject section */ 306 | 307 | /* Begin PBXResourcesBuildPhase section */ 308 | 0A46FE97156FA72300D97F26 /* Resources */ = { 309 | isa = PBXResourcesBuildPhase; 310 | buildActionMask = 2147483647; 311 | files = ( 312 | 0A46FEA8156FA72300D97F26 /* InfoPlist.strings in Resources */, 313 | 0A46FEB1156FA72300D97F26 /* MainStoryboard.storyboard in Resources */, 314 | 0A1479A316C2958F00D3B69D /* Default-568h@2x.png in Resources */, 315 | ); 316 | runOnlyForDeploymentPostprocessing = 0; 317 | }; 318 | 0A46FEB7156FA72300D97F26 /* Resources */ = { 319 | isa = PBXResourcesBuildPhase; 320 | buildActionMask = 2147483647; 321 | files = ( 322 | 0A46FEC6156FA72300D97F26 /* InfoPlist.strings in Resources */, 323 | ); 324 | runOnlyForDeploymentPostprocessing = 0; 325 | }; 326 | 1DA6EDF71A6E0A6C00F2510C /* Resources */ = { 327 | isa = PBXResourcesBuildPhase; 328 | buildActionMask = 2147483647; 329 | files = ( 330 | ); 331 | runOnlyForDeploymentPostprocessing = 0; 332 | }; 333 | /* End PBXResourcesBuildPhase section */ 334 | 335 | /* Begin PBXShellScriptBuildPhase section */ 336 | 0A46FEB8156FA72300D97F26 /* ShellScript */ = { 337 | isa = PBXShellScriptBuildPhase; 338 | buildActionMask = 2147483647; 339 | files = ( 340 | ); 341 | inputPaths = ( 342 | ); 343 | outputPaths = ( 344 | ); 345 | runOnlyForDeploymentPostprocessing = 0; 346 | shellPath = /bin/sh; 347 | shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n"; 348 | }; 349 | /* End PBXShellScriptBuildPhase section */ 350 | 351 | /* Begin PBXSourcesBuildPhase section */ 352 | 0A46FE95156FA72300D97F26 /* Sources */ = { 353 | isa = PBXSourcesBuildPhase; 354 | buildActionMask = 2147483647; 355 | files = ( 356 | 0A46FEAA156FA72300D97F26 /* main.m in Sources */, 357 | 0A46FEAE156FA72300D97F26 /* AppDelegate.m in Sources */, 358 | 0A46FEB4156FA72300D97F26 /* ViewController.m in Sources */, 359 | 0A46FEDA156FA8D900D97F26 /* RavenClient.m in Sources */, 360 | 8BAEC13E168E6FC100408CDB /* RavenConfig.m in Sources */, 361 | ); 362 | runOnlyForDeploymentPostprocessing = 0; 363 | }; 364 | 0A46FEB5156FA72300D97F26 /* Sources */ = { 365 | isa = PBXSourcesBuildPhase; 366 | buildActionMask = 2147483647; 367 | files = ( 368 | 8BAEC154168E747900408CDB /* RavenClient.m in Sources */, 369 | 8BAEC156168E748700408CDB /* RavenConfig.m in Sources */, 370 | 0A46FEC9156FA72300D97F26 /* RavenClientTest.m in Sources */, 371 | 8BAEC142168E725100408CDB /* RavenConfigTest.m in Sources */, 372 | ); 373 | runOnlyForDeploymentPostprocessing = 0; 374 | }; 375 | 1DA6EDF41A6E0A6C00F2510C /* Sources */ = { 376 | isa = PBXSourcesBuildPhase; 377 | buildActionMask = 2147483647; 378 | files = ( 379 | 1DA6EE121A6E0AD400F2510C /* RavenClient.m in Sources */, 380 | 1DA6EE131A6E0AD600F2510C /* RavenConfig.m in Sources */, 381 | ); 382 | runOnlyForDeploymentPostprocessing = 0; 383 | }; 384 | /* End PBXSourcesBuildPhase section */ 385 | 386 | /* Begin PBXVariantGroup section */ 387 | 0A46FEA6156FA72300D97F26 /* InfoPlist.strings */ = { 388 | isa = PBXVariantGroup; 389 | children = ( 390 | 0A46FEA7156FA72300D97F26 /* en */, 391 | ); 392 | name = InfoPlist.strings; 393 | sourceTree = ""; 394 | }; 395 | 0A46FEAF156FA72300D97F26 /* MainStoryboard.storyboard */ = { 396 | isa = PBXVariantGroup; 397 | children = ( 398 | 0A46FEB0156FA72300D97F26 /* en */, 399 | ); 400 | name = MainStoryboard.storyboard; 401 | sourceTree = ""; 402 | }; 403 | 0A46FEC4156FA72300D97F26 /* InfoPlist.strings */ = { 404 | isa = PBXVariantGroup; 405 | children = ( 406 | 0A46FEC5156FA72300D97F26 /* en */, 407 | ); 408 | name = InfoPlist.strings; 409 | sourceTree = ""; 410 | }; 411 | /* End PBXVariantGroup section */ 412 | 413 | /* Begin XCBuildConfiguration section */ 414 | 0A46FECA156FA72300D97F26 /* Debug */ = { 415 | isa = XCBuildConfiguration; 416 | buildSettings = { 417 | ALWAYS_SEARCH_USER_PATHS = NO; 418 | CLANG_ENABLE_OBJC_ARC = YES; 419 | CLANG_WARN_BOOL_CONVERSION = YES; 420 | CLANG_WARN_CONSTANT_CONVERSION = YES; 421 | CLANG_WARN_EMPTY_BODY = YES; 422 | CLANG_WARN_ENUM_CONVERSION = YES; 423 | CLANG_WARN_INT_CONVERSION = YES; 424 | CLANG_WARN_UNREACHABLE_CODE = YES; 425 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 426 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 427 | COPY_PHASE_STRIP = NO; 428 | ENABLE_STRICT_OBJC_MSGSEND = YES; 429 | ENABLE_TESTABILITY = YES; 430 | GCC_C_LANGUAGE_STANDARD = gnu99; 431 | GCC_DYNAMIC_NO_PIC = NO; 432 | GCC_NO_COMMON_BLOCKS = YES; 433 | GCC_OPTIMIZATION_LEVEL = 0; 434 | GCC_PREPROCESSOR_DEFINITIONS = ( 435 | "DEBUG=1", 436 | "$(inherited)", 437 | ); 438 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 439 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 440 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 441 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 442 | GCC_WARN_UNDECLARED_SELECTOR = YES; 443 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 444 | GCC_WARN_UNUSED_FUNCTION = YES; 445 | GCC_WARN_UNUSED_VARIABLE = YES; 446 | IPHONEOS_DEPLOYMENT_TARGET = 5.1; 447 | ONLY_ACTIVE_ARCH = YES; 448 | SDKROOT = iphoneos; 449 | TARGETED_DEVICE_FAMILY = "1,2"; 450 | }; 451 | name = Debug; 452 | }; 453 | 0A46FECB156FA72300D97F26 /* Release */ = { 454 | isa = XCBuildConfiguration; 455 | buildSettings = { 456 | ALWAYS_SEARCH_USER_PATHS = NO; 457 | CLANG_ENABLE_OBJC_ARC = YES; 458 | CLANG_WARN_BOOL_CONVERSION = YES; 459 | CLANG_WARN_CONSTANT_CONVERSION = YES; 460 | CLANG_WARN_EMPTY_BODY = YES; 461 | CLANG_WARN_ENUM_CONVERSION = YES; 462 | CLANG_WARN_INT_CONVERSION = YES; 463 | CLANG_WARN_UNREACHABLE_CODE = YES; 464 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 465 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 466 | COPY_PHASE_STRIP = YES; 467 | ENABLE_STRICT_OBJC_MSGSEND = YES; 468 | GCC_C_LANGUAGE_STANDARD = gnu99; 469 | GCC_NO_COMMON_BLOCKS = YES; 470 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 471 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 472 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 473 | GCC_WARN_UNDECLARED_SELECTOR = YES; 474 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 475 | GCC_WARN_UNUSED_FUNCTION = YES; 476 | GCC_WARN_UNUSED_VARIABLE = YES; 477 | IPHONEOS_DEPLOYMENT_TARGET = 5.1; 478 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 479 | SDKROOT = iphoneos; 480 | TARGETED_DEVICE_FAMILY = "1,2"; 481 | VALIDATE_PRODUCT = YES; 482 | }; 483 | name = Release; 484 | }; 485 | 0A46FECD156FA72300D97F26 /* Debug */ = { 486 | isa = XCBuildConfiguration; 487 | buildSettings = { 488 | CLANG_ENABLE_OBJC_ARC = YES; 489 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 490 | GCC_PREFIX_HEADER = "Example/Raven-Prefix.pch"; 491 | GCC_VERSION = ""; 492 | INFOPLIST_FILE = "Example/Raven-Info.plist"; 493 | ONLY_ACTIVE_ARCH = YES; 494 | PRODUCT_BUNDLE_IDENTIFIER = "nl.mixedCase.${PRODUCT_NAME:rfc1034identifier}"; 495 | PRODUCT_NAME = "$(TARGET_NAME)"; 496 | WRAPPER_EXTENSION = app; 497 | }; 498 | name = Debug; 499 | }; 500 | 0A46FECE156FA72300D97F26 /* Release */ = { 501 | isa = XCBuildConfiguration; 502 | buildSettings = { 503 | CLANG_ENABLE_OBJC_ARC = YES; 504 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 505 | GCC_PREFIX_HEADER = "Example/Raven-Prefix.pch"; 506 | GCC_VERSION = ""; 507 | INFOPLIST_FILE = "Example/Raven-Info.plist"; 508 | PRODUCT_BUNDLE_IDENTIFIER = "nl.mixedCase.${PRODUCT_NAME:rfc1034identifier}"; 509 | PRODUCT_NAME = "$(TARGET_NAME)"; 510 | WRAPPER_EXTENSION = app; 511 | }; 512 | name = Release; 513 | }; 514 | 0A46FED0156FA72300D97F26 /* Debug */ = { 515 | isa = XCBuildConfiguration; 516 | buildSettings = { 517 | BUNDLE_LOADER = ""; 518 | FRAMEWORK_SEARCH_PATHS = ( 519 | "${inherited}", 520 | "\"$(SDKROOT)/Developer/Library/Frameworks\"", 521 | "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", 522 | "$(inherited)", 523 | ); 524 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 525 | GCC_PREFIX_HEADER = "Example/Raven-Prefix.pch"; 526 | GCC_VERSION = ""; 527 | INFOPLIST_FILE = "RavenTests/RavenTests-Info.plist"; 528 | ONLY_ACTIVE_ARCH = YES; 529 | PRODUCT_BUNDLE_IDENTIFIER = "nl.mixedCase.${PRODUCT_NAME:rfc1034identifier}"; 530 | PRODUCT_NAME = "$(TARGET_NAME)"; 531 | TARGETED_DEVICE_FAMILY = "1,2"; 532 | TEST_HOST = "$(BUNDLE_LOADER)"; 533 | }; 534 | name = Debug; 535 | }; 536 | 0A46FED1156FA72300D97F26 /* Release */ = { 537 | isa = XCBuildConfiguration; 538 | buildSettings = { 539 | BUNDLE_LOADER = ""; 540 | FRAMEWORK_SEARCH_PATHS = ( 541 | "${inherited}", 542 | "\"$(SDKROOT)/Developer/Library/Frameworks\"", 543 | "\"$(DEVELOPER_LIBRARY_DIR)/Frameworks\"", 544 | "$(inherited)", 545 | ); 546 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 547 | GCC_PREFIX_HEADER = "Example/Raven-Prefix.pch"; 548 | GCC_VERSION = ""; 549 | INFOPLIST_FILE = "RavenTests/RavenTests-Info.plist"; 550 | PRODUCT_BUNDLE_IDENTIFIER = "nl.mixedCase.${PRODUCT_NAME:rfc1034identifier}"; 551 | PRODUCT_NAME = "$(TARGET_NAME)"; 552 | TARGETED_DEVICE_FAMILY = "1,2"; 553 | TEST_HOST = "$(BUNDLE_LOADER)"; 554 | }; 555 | name = Release; 556 | }; 557 | 1DA6EE0C1A6E0A6C00F2510C /* Debug */ = { 558 | isa = XCBuildConfiguration; 559 | buildSettings = { 560 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 561 | CLANG_CXX_LIBRARY = "libc++"; 562 | CLANG_ENABLE_MODULES = YES; 563 | CLANG_WARN_BOOL_CONVERSION = YES; 564 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 565 | CLANG_WARN_EMPTY_BODY = YES; 566 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 567 | CLANG_WARN_UNREACHABLE_CODE = YES; 568 | CURRENT_PROJECT_VERSION = 1; 569 | DEFINES_MODULE = YES; 570 | DYLIB_COMPATIBILITY_VERSION = 1; 571 | DYLIB_CURRENT_VERSION = 1; 572 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 573 | ENABLE_STRICT_OBJC_MSGSEND = YES; 574 | GCC_PREPROCESSOR_DEFINITIONS = ( 575 | "DEBUG=1", 576 | "$(inherited)", 577 | ); 578 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 579 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 580 | GCC_WARN_UNDECLARED_SELECTOR = YES; 581 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 582 | GCC_WARN_UNUSED_FUNCTION = YES; 583 | INFOPLIST_FILE = Raven/Info.plist; 584 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 585 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 586 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 587 | MTL_ENABLE_DEBUG_INFO = YES; 588 | ONLY_ACTIVE_ARCH = YES; 589 | PRODUCT_BUNDLE_IDENTIFIER = "nl.mixedCase.$(PRODUCT_NAME:rfc1034identifier)"; 590 | PRODUCT_NAME = Raven; 591 | SKIP_INSTALL = YES; 592 | VERSIONING_SYSTEM = "apple-generic"; 593 | VERSION_INFO_PREFIX = ""; 594 | }; 595 | name = Debug; 596 | }; 597 | 1DA6EE0D1A6E0A6C00F2510C /* Release */ = { 598 | isa = XCBuildConfiguration; 599 | buildSettings = { 600 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 601 | CLANG_CXX_LIBRARY = "libc++"; 602 | CLANG_ENABLE_MODULES = YES; 603 | CLANG_WARN_BOOL_CONVERSION = YES; 604 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 605 | CLANG_WARN_EMPTY_BODY = YES; 606 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 607 | CLANG_WARN_UNREACHABLE_CODE = YES; 608 | COPY_PHASE_STRIP = NO; 609 | CURRENT_PROJECT_VERSION = 1; 610 | DEFINES_MODULE = YES; 611 | DYLIB_COMPATIBILITY_VERSION = 1; 612 | DYLIB_CURRENT_VERSION = 1; 613 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 614 | ENABLE_NS_ASSERTIONS = NO; 615 | ENABLE_STRICT_OBJC_MSGSEND = YES; 616 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 617 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 618 | GCC_WARN_UNDECLARED_SELECTOR = YES; 619 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 620 | GCC_WARN_UNUSED_FUNCTION = YES; 621 | INFOPLIST_FILE = Raven/Info.plist; 622 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 623 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 624 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 625 | MTL_ENABLE_DEBUG_INFO = NO; 626 | PRODUCT_BUNDLE_IDENTIFIER = "nl.mixedCase.$(PRODUCT_NAME:rfc1034identifier)"; 627 | PRODUCT_NAME = Raven; 628 | SKIP_INSTALL = YES; 629 | VERSIONING_SYSTEM = "apple-generic"; 630 | VERSION_INFO_PREFIX = ""; 631 | }; 632 | name = Release; 633 | }; 634 | /* End XCBuildConfiguration section */ 635 | 636 | /* Begin XCConfigurationList section */ 637 | 0A46FE93156FA72300D97F26 /* Build configuration list for PBXProject "Raven" */ = { 638 | isa = XCConfigurationList; 639 | buildConfigurations = ( 640 | 0A46FECA156FA72300D97F26 /* Debug */, 641 | 0A46FECB156FA72300D97F26 /* Release */, 642 | ); 643 | defaultConfigurationIsVisible = 0; 644 | defaultConfigurationName = Release; 645 | }; 646 | 0A46FECC156FA72300D97F26 /* Build configuration list for PBXNativeTarget "RavenExample" */ = { 647 | isa = XCConfigurationList; 648 | buildConfigurations = ( 649 | 0A46FECD156FA72300D97F26 /* Debug */, 650 | 0A46FECE156FA72300D97F26 /* Release */, 651 | ); 652 | defaultConfigurationIsVisible = 0; 653 | defaultConfigurationName = Release; 654 | }; 655 | 0A46FECF156FA72300D97F26 /* Build configuration list for PBXNativeTarget "RavenTests" */ = { 656 | isa = XCConfigurationList; 657 | buildConfigurations = ( 658 | 0A46FED0156FA72300D97F26 /* Debug */, 659 | 0A46FED1156FA72300D97F26 /* Release */, 660 | ); 661 | defaultConfigurationIsVisible = 0; 662 | defaultConfigurationName = Release; 663 | }; 664 | 1DA6EE101A6E0A6C00F2510C /* Build configuration list for PBXNativeTarget "Raven (iOS)" */ = { 665 | isa = XCConfigurationList; 666 | buildConfigurations = ( 667 | 1DA6EE0C1A6E0A6C00F2510C /* Debug */, 668 | 1DA6EE0D1A6E0A6C00F2510C /* Release */, 669 | ); 670 | defaultConfigurationIsVisible = 0; 671 | defaultConfigurationName = Release; 672 | }; 673 | /* End XCConfigurationList section */ 674 | }; 675 | rootObject = 0A46FE90156FA72300D97F26 /* Project object */; 676 | } 677 | -------------------------------------------------------------------------------- /Raven.xcodeproj/xcshareddata/xcschemes/Raven (iOS).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 | -------------------------------------------------------------------------------- /Raven.xcodeproj/xcshareddata/xcschemes/RavenTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 74 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /Raven/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 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Raven/Raven.h: -------------------------------------------------------------------------------- 1 | // 2 | // Raven.h 3 | // Raven 4 | // 5 | // Created by Fjölnir Ásgeirsson on 1/20/15. 6 | // Copyright (c) 2015 Gangverk. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | FOUNDATION_EXPORT double RavenVersionNumber; 13 | FOUNDATION_EXPORT const unsigned char RavenVersionString[]; 14 | -------------------------------------------------------------------------------- /Raven/RavenClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // RavenClient.h 3 | // Raven 4 | // 5 | // Created by Kevin Renskers on 25-05-12. 6 | // Copyright (c) 2012 Gangverk. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #define RavenCaptureMessage( s, ... ) [[RavenClient sharedClient] captureMessage:[NSString stringWithFormat:(s), ##__VA_ARGS__] level:kRavenLogLevelDebugInfo method:__FUNCTION__ file:__FILE__ line:__LINE__] 12 | 13 | #define RavenCaptureError(error) [[RavenClient sharedClient] captureMessage:[NSString stringWithFormat:@"%@", error] \ 14 | level:kRavenLogLevelDebugError \ 15 | additionalExtra:nil \ 16 | additionalTags:nil \ 17 | method:__FUNCTION__ \ 18 | file:__FILE__ \ 19 | line:__LINE__]; 20 | 21 | #define RavenCaptureNetworkError(error) [[RavenClient sharedClient] captureMessage:[NSString stringWithFormat:@"%@", error] \ 22 | level:kRavenLogLevelDebugError \ 23 | additionalExtra:nil \ 24 | additionalTags:nil \ 25 | method:__FUNCTION__ \ 26 | file:__FILE__ \ 27 | line:__LINE__ \ 28 | sendNow:NO]; 29 | 30 | #define RavenCaptureException(exception) [[RavenClient sharedClient] captureException:exception method:__FUNCTION__ file:__FILE__ line:__LINE__ sendNow:YES]; 31 | 32 | 33 | typedef enum { 34 | kRavenLogLevelDebug, 35 | kRavenLogLevelDebugInfo, 36 | kRavenLogLevelDebugWarning, 37 | kRavenLogLevelDebugError, 38 | kRavenLogLevelDebugFatal 39 | } RavenLogLevel; 40 | 41 | 42 | @interface RavenClient : NSObject 43 | 44 | @property (strong, nonatomic) NSDictionary *extra; 45 | @property (strong, nonatomic) NSDictionary *tags; 46 | @property (strong, nonatomic) NSString *logger; 47 | @property (strong, nonatomic) NSDictionary *user; 48 | @property (assign, nonatomic) BOOL debugMode; 49 | 50 | /** 51 | * By setting tags with setTags: selector it will also set default settings: 52 | * - Build version 53 | * - OS version (on iOS) 54 | * - Device model (on iOS) 55 | * 56 | * For full control use this method. 57 | */ 58 | - (void)setTags:(NSDictionary *)tags withDefaultValues:(BOOL)withDefaultValues; 59 | 60 | - (void)setRelease:(NSString *)release; 61 | 62 | // Singleton and initializers 63 | + (RavenClient *)clientWithDSN:(NSString *)DSN; 64 | + (RavenClient *)clientWithDSN:(NSString *)DSN extra:(NSDictionary *)extra; 65 | + (RavenClient *)clientWithDSN:(NSString *)DSN extra:(NSDictionary *)extra tags:(NSDictionary *)tags; 66 | + (RavenClient *)clientWithDSN:(NSString *)DSN extra:(NSDictionary *)extra tags:(NSDictionary *)tags logger:(NSString *)logger; 67 | 68 | + (instancetype)sharedClient; 69 | + (void)setSharedClient:(RavenClient *)client; 70 | 71 | - (instancetype)initWithDSN:(NSString *)DSN; 72 | - (instancetype)initWithDSN:(NSString *)DSN extra:(NSDictionary *)extra; 73 | - (instancetype)initWithDSN:(NSString *)DSN extra:(NSDictionary *)extra tags:(NSDictionary *)tags; 74 | - (instancetype)initWithDSN:(NSString *)DSN extra:(NSDictionary *)extra tags:(NSDictionary *)tags logger:(NSString *)logger; 75 | 76 | /** 77 | * Messages 78 | * 79 | * All entries from additionalExtra/additionalTags are added to extra/tags. 80 | * 81 | * If dictionaries contain the same key, the entries from extra/tags dictionaries will be replaced with entries 82 | * from additionalExtra/additionalTags dictionaries. 83 | */ 84 | - (void)captureMessage:(NSString *)message; 85 | - (void)captureMessage:(NSString *)message level:(RavenLogLevel)level; 86 | - (void)captureMessage:(NSString *)message level:(RavenLogLevel)level method:(const char *)method file:(const char *)file line:(NSInteger)line; 87 | - (void)captureMessage:(NSString *)message level:(RavenLogLevel)level additionalExtra:(NSDictionary *)additionalExtra additionalTags:(NSDictionary *)additionalTags; 88 | 89 | - (void)captureMessage:(NSString *)message 90 | level:(RavenLogLevel)level 91 | additionalExtra:(NSDictionary *)additionalExtra 92 | additionalTags:(NSDictionary *)additionalTags 93 | method:(const char *)method 94 | file:(const char *)file 95 | line:(NSInteger)line; 96 | 97 | - (void)captureMessage:(NSString *)message 98 | level:(RavenLogLevel)level 99 | additionalExtra:(NSDictionary *)additionalExtra 100 | additionalTags:(NSDictionary *)additionalTags 101 | method:(const char *)method 102 | file:(const char *)file 103 | line:(NSInteger)line 104 | sendNow:(BOOL)sendNow; 105 | 106 | - (void)captureMessage:(NSString *)message 107 | level:(RavenLogLevel)level 108 | additionalExtra:(NSDictionary *)additionalExtra 109 | additionalTags:(NSDictionary *)additionalTags 110 | stacktrace:(NSArray *)stacktrace 111 | culprit:(NSString *)culprit 112 | sendNow:(BOOL)sendNow; 113 | 114 | /** 115 | * Exceptions 116 | * 117 | * All entries from additionalExtra/additionalTags are added to extra/tags. 118 | * 119 | * If dictionaries contain the same key, the entries from extra/tags dictionaries will be replaced with entries 120 | * from additionalExtra/additionalTags dictionaries. 121 | */ 122 | - (void)captureException:(NSException *)exception; 123 | - (void)captureException:(NSException *)exception sendNow:(BOOL)sendNow; 124 | - (void)captureException:(NSException *)exception additionalExtra:(NSDictionary *)additionalExtra additionalTags:(NSDictionary *)additionalTags sendNow:(BOOL)sendNow; 125 | - (void)captureException:(NSException*)exception method:(const char*)method file:(const char*)file line:(NSInteger)line sendNow:(BOOL)sendNow; 126 | - (void)setupExceptionHandler; 127 | 128 | @end 129 | -------------------------------------------------------------------------------- /Raven/RavenClient.m: -------------------------------------------------------------------------------- 1 | // 2 | // RavenClient.m 3 | // Raven 4 | // 5 | // Created by Kevin Renskers on 25-05-12. 6 | // Copyright (c) 2012 Gangverk. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "RavenClient.h" 11 | #import "RavenClient_Private.h" 12 | #import "RavenConfig.h" 13 | 14 | #if TARGET_OS_IPHONE 15 | #import 16 | #endif 17 | 18 | NSString *const kRavenLogLevelArray[] = { 19 | @"debug", 20 | @"info", 21 | @"warning", 22 | @"error", 23 | @"fatal" 24 | }; 25 | 26 | NSString *const userDefaultsKey = @"nl.mixedCase.RavenClient.Exceptions"; 27 | NSString *const sentryProtocol = @"7"; 28 | NSString *const sentryClient = @"raven-objc/0.5.0"; 29 | 30 | static RavenClient *sharedClient = nil; 31 | 32 | @implementation RavenClient { 33 | NSString *_release; 34 | } 35 | 36 | void exceptionHandler(NSException *exception) { 37 | [[RavenClient sharedClient] captureException:exception sendNow:NO]; 38 | } 39 | 40 | #pragma mark - Setters and getters 41 | 42 | - (NSDateFormatter *)dateFormatter { 43 | if (!_dateFormatter) { 44 | NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"UTC"]; 45 | _dateFormatter = [[NSDateFormatter alloc] init]; 46 | [_dateFormatter setTimeZone:timeZone]; 47 | [_dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"]; 48 | } 49 | 50 | return _dateFormatter; 51 | } 52 | 53 | - (void)setRelease:(NSString *)newRelease { 54 | _release = newRelease; 55 | } 56 | 57 | - (void)setTags:(NSDictionary *)tags { 58 | [self setTags:tags withDefaultValues:YES]; 59 | } 60 | 61 | - (void)setTags:(NSDictionary *)tags withDefaultValues:(BOOL)withDefaultValues { 62 | NSMutableDictionary *mTags = [[NSMutableDictionary alloc] initWithDictionary:tags]; 63 | 64 | if (withDefaultValues && ![mTags objectForKey:@"Build version"]) { 65 | NSString *buildVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; 66 | if (buildVersion) { 67 | [mTags setObject:buildVersion forKey:@"Build version"]; 68 | } 69 | } 70 | 71 | #if TARGET_OS_IPHONE 72 | if (withDefaultValues && ![mTags objectForKey:@"OS version"]) { 73 | NSString *osVersion = [[UIDevice currentDevice] systemVersion]; 74 | [mTags setObject:osVersion forKey:@"OS version"]; 75 | } 76 | 77 | if (withDefaultValues && ![mTags objectForKey:@"Device model"]) { 78 | struct utsname systemInfo; 79 | uname(&systemInfo); 80 | NSString *deviceModel = [NSString stringWithCString:systemInfo.machine 81 | encoding:NSUTF8StringEncoding]; 82 | [mTags setObject:deviceModel forKey:@"Device model"]; 83 | } 84 | #endif 85 | 86 | _tags = mTags; 87 | } 88 | 89 | #pragma mark - Singleton and initializers 90 | 91 | + (RavenClient *)clientWithDSN:(NSString *)DSN { 92 | return [[self alloc] initWithDSN:DSN]; 93 | } 94 | 95 | + (RavenClient *)clientWithDSN:(NSString *)DSN extra:(NSDictionary *)extra { 96 | return [[self alloc] initWithDSN:DSN extra:extra]; 97 | } 98 | 99 | + (RavenClient *)clientWithDSN:(NSString *)DSN extra:(NSDictionary *)extra tags:(NSDictionary *)tags { 100 | return [[self alloc] initWithDSN:DSN extra:extra tags:tags]; 101 | } 102 | 103 | + (RavenClient *)clientWithDSN:(NSString *)DSN extra:(NSDictionary *)extra tags:(NSDictionary *)tags logger:(NSString *)logger { 104 | return [[self alloc] initWithDSN:DSN extra:extra tags:tags logger:logger]; 105 | } 106 | 107 | + (RavenClient *)sharedClient { 108 | return sharedClient; 109 | } 110 | 111 | + (void)setSharedClient:(RavenClient *)client { 112 | sharedClient = client; 113 | } 114 | 115 | - (instancetype)initWithDSN:(NSString *)DSN { 116 | return [self initWithDSN:DSN extra:@{}]; 117 | } 118 | 119 | - (instancetype)initWithDSN:(NSString *)DSN extra:(NSDictionary *)extra { 120 | return [self initWithDSN:DSN extra:extra tags:@{}]; 121 | } 122 | 123 | - (instancetype)initWithDSN:(NSString *)DSN extra:(NSDictionary *)extra tags:(NSDictionary *)tags { 124 | return [self initWithDSN:DSN extra:extra tags:tags logger:nil]; 125 | } 126 | 127 | - (instancetype)initWithDSN:(NSString *)DSN extra:(NSDictionary *)extra tags:(NSDictionary *)tags logger:(NSString *)logger { 128 | self = [super init]; 129 | if (self) { 130 | if (DSN) 131 | _config = [[RavenConfig alloc] init]; 132 | _extra = extra; 133 | _logger = logger; 134 | self.tags = tags; 135 | 136 | // bind release 137 | NSString *buildVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; 138 | if (buildVersion) { 139 | _release = buildVersion; 140 | } 141 | 142 | // Parse DSN 143 | if (_config && ![_config setDSN:DSN]) { 144 | NSLog(@"Invalid DSN %@!", DSN); 145 | return nil; 146 | } 147 | } 148 | 149 | return self; 150 | } 151 | 152 | #pragma mark - Messages 153 | 154 | - (void)captureMessage:(NSString *)message { 155 | [self captureMessage:message level:kRavenLogLevelDebugInfo]; 156 | } 157 | 158 | - (void)captureMessage:(NSString *)message level:(RavenLogLevel)level { 159 | [self captureMessage:message level:level method:nil file:nil line:0]; 160 | } 161 | 162 | - (void)captureMessage:(NSString *)message level:(RavenLogLevel)level method:(const char *)method file:(const char *)file line:(NSInteger)line { 163 | 164 | [self captureMessage:message level:level additionalExtra:nil additionalTags:nil method:method file:file line:line]; 165 | } 166 | 167 | - (void)captureMessage:(NSString *)message level:(RavenLogLevel)level additionalExtra:(NSDictionary *)additionalExtra additionalTags:(NSDictionary *)additionalTags { 168 | [self captureMessage:message level:level additionalExtra:additionalExtra additionalTags:additionalTags method:nil file:nil line:0]; 169 | } 170 | 171 | - (void)captureMessage:(NSString *)message 172 | level:(RavenLogLevel)level 173 | additionalExtra:(NSDictionary *)additionalExtra 174 | additionalTags:(NSDictionary *)additionalTags 175 | method:(const char *)method 176 | file:(const char *)file 177 | line:(NSInteger)line { 178 | 179 | [self captureMessage:message level:level additionalExtra:additionalExtra additionalTags:additionalTags method:method file:file line:line sendNow:YES]; 180 | } 181 | 182 | - (void)captureMessage:(NSString *)message 183 | level:(RavenLogLevel)level 184 | additionalExtra:(NSDictionary *)additionalExtra 185 | additionalTags:(NSDictionary *)additionalTags 186 | method:(const char *)method 187 | file:(const char *)file 188 | line:(NSInteger)line 189 | sendNow:(BOOL)sendNow { 190 | 191 | NSArray *stacktrace; 192 | NSString *culprit; 193 | if (method && file && line) { 194 | NSString *filename = [[NSString stringWithUTF8String:file] lastPathComponent]; 195 | NSString *methodString = [NSString stringWithUTF8String:method]; 196 | NSDictionary *frame = [NSDictionary dictionaryWithObjectsAndKeys: 197 | filename, @"filename", 198 | methodString, @"function", 199 | [NSNumber numberWithInteger:line], @"lineno", 200 | nil]; 201 | 202 | stacktrace = [NSArray arrayWithObject:frame]; 203 | 204 | culprit = [NSString stringWithFormat:@"%@ / %@", filename, methodString]; 205 | } 206 | [self captureMessage:message level:level additionalExtra:additionalExtra additionalTags:additionalTags stacktrace:stacktrace culprit:culprit sendNow:sendNow]; 207 | } 208 | 209 | - (void)captureMessage:(NSString *)message 210 | level:(RavenLogLevel)level 211 | additionalExtra:(NSDictionary *)additionalExtra 212 | additionalTags:(NSDictionary *)additionalTags 213 | stacktrace:(NSArray *)stacktrace 214 | culprit:(NSString *)culprit 215 | sendNow:(BOOL)sendNow { 216 | NSDictionary *data = [self prepareDictionaryForMessage:message 217 | level:level 218 | additionalExtra:additionalExtra 219 | additionalTags:additionalTags 220 | culprit:culprit 221 | stacktrace:stacktrace 222 | exception:nil]; 223 | 224 | if (!sendNow) { 225 | // We can't send this message to Sentry now, e.g. because the error was network related and the user may not have a data connection So, save it into NSUserDefaults. 226 | NSArray *reports = [[NSUserDefaults standardUserDefaults] objectForKey:userDefaultsKey]; 227 | if (reports != nil) { 228 | NSMutableArray *reportsCopy = [reports mutableCopy]; 229 | [reportsCopy addObject:data]; 230 | [[NSUserDefaults standardUserDefaults] setObject:reportsCopy forKey:userDefaultsKey]; 231 | } else { 232 | reports = [NSArray arrayWithObject:data]; 233 | [[NSUserDefaults standardUserDefaults] setObject:reports forKey:userDefaultsKey]; 234 | } 235 | [[NSUserDefaults standardUserDefaults] synchronize]; 236 | } else { 237 | [self sendDictionary:data]; 238 | } 239 | } 240 | 241 | 242 | 243 | #pragma mark - Exceptions 244 | 245 | - (void)captureException:(NSException *)exception { 246 | [self captureException:exception sendNow:YES]; 247 | } 248 | 249 | - (void)captureException:(NSException *)exception sendNow:(BOOL)sendNow { 250 | [self captureException:exception additionalExtra:nil additionalTags:nil sendNow:sendNow]; 251 | } 252 | 253 | - (void)captureException:(NSException *)exception additionalExtra:(NSDictionary *)additionalExtra additionalTags:(NSDictionary *)additionalTags sendNow:(BOOL)sendNow { 254 | NSString *message = [NSString stringWithFormat:@"%@: %@", exception.name, exception.reason]; 255 | 256 | NSDictionary *exceptionDict = [NSDictionary dictionaryWithObjectsAndKeys: 257 | exception.name, @"type", 258 | exception.reason, @"value", 259 | nil]; 260 | 261 | NSArray *callStack = [exception callStackSymbols]; 262 | NSMutableArray *stacktrace = [[NSMutableArray alloc] initWithCapacity:[callStack count]]; 263 | for (NSString *call in callStack) { 264 | [stacktrace addObject:[NSDictionary dictionaryWithObjectsAndKeys:call, @"function", nil]]; 265 | } 266 | 267 | NSDictionary *data = [self prepareDictionaryForMessage:message 268 | level:kRavenLogLevelDebugFatal 269 | additionalExtra:additionalExtra 270 | additionalTags:additionalTags 271 | culprit:nil 272 | stacktrace:stacktrace 273 | exception:exceptionDict]; 274 | 275 | if (!sendNow) { 276 | // We can't send this exception to Sentry now, e.g. because the app is killed before the 277 | // connection can be made. So, save it into NSUserDefaults. 278 | NSArray *reports = [[NSUserDefaults standardUserDefaults] objectForKey:userDefaultsKey]; 279 | if (reports != nil) { 280 | NSMutableArray *reportsCopy = [reports mutableCopy]; 281 | [reportsCopy addObject:data]; 282 | [[NSUserDefaults standardUserDefaults] setObject:reportsCopy forKey:userDefaultsKey]; 283 | } else { 284 | reports = [NSArray arrayWithObject:data]; 285 | [[NSUserDefaults standardUserDefaults] setObject:reports forKey:userDefaultsKey]; 286 | } 287 | [[NSUserDefaults standardUserDefaults] synchronize]; 288 | } else { 289 | [self sendDictionary:data]; 290 | } 291 | } 292 | 293 | - (void)captureException:(NSException *)exception method:(const char *)method file:(const char *)file line:(NSInteger)line sendNow:(BOOL)sendNow { 294 | NSString *message = [NSString stringWithFormat:@"%@: %@", exception.name, exception.reason]; 295 | 296 | NSDictionary *exceptionDict = [NSDictionary dictionaryWithObjectsAndKeys: 297 | exception.name, @"type", 298 | exception.reason, @"value", 299 | nil]; 300 | 301 | NSArray *callStack = [exception callStackSymbols]; 302 | NSMutableArray *stacktrace; 303 | if (method && file && line) { 304 | NSDictionary *frame = [NSDictionary dictionaryWithObjectsAndKeys: 305 | [[NSString stringWithUTF8String:file] lastPathComponent], @"filename", 306 | [NSString stringWithUTF8String:method], @"function", 307 | [NSNumber numberWithInteger:line], @"lineno", 308 | nil]; 309 | 310 | stacktrace = [NSMutableArray arrayWithObject:frame]; 311 | } 312 | for (NSString *call in callStack) { 313 | [stacktrace addObject:[NSDictionary dictionaryWithObjectsAndKeys:call, @"function", nil]]; 314 | } 315 | 316 | NSDictionary *data = [self prepareDictionaryForMessage:message 317 | level:kRavenLogLevelDebugFatal 318 | additionalExtra:nil 319 | additionalTags:nil 320 | culprit:nil 321 | stacktrace:stacktrace 322 | exception:exceptionDict]; 323 | 324 | if (!sendNow) { 325 | // We can't send this exception to Sentry now, e.g. because the app is killed before the 326 | // connection can be made. So, save it into NSUserDefaults. 327 | NSArray *reports = [[NSUserDefaults standardUserDefaults] objectForKey:userDefaultsKey]; 328 | if (reports != nil) { 329 | NSMutableArray *reportsCopy = [reports mutableCopy]; 330 | [reportsCopy addObject:data]; 331 | [[NSUserDefaults standardUserDefaults] setObject:reportsCopy forKey:userDefaultsKey]; 332 | } else { 333 | reports = [NSArray arrayWithObject:data]; 334 | [[NSUserDefaults standardUserDefaults] setObject:reports forKey:userDefaultsKey]; 335 | } 336 | [[NSUserDefaults standardUserDefaults] synchronize]; 337 | } else { 338 | [self sendDictionary:data]; 339 | } 340 | } 341 | 342 | - (void)setupExceptionHandler { 343 | NSSetUncaughtExceptionHandler(&exceptionHandler); 344 | 345 | // Process saved crash reports 346 | NSArray *reports = [[NSUserDefaults standardUserDefaults] objectForKey:userDefaultsKey]; 347 | if (reports != nil && [reports count]) { 348 | for (NSDictionary *data in reports) { 349 | [self sendDictionary:data]; 350 | } 351 | [[NSUserDefaults standardUserDefaults] setObject:[NSArray array] forKey:userDefaultsKey]; 352 | [[NSUserDefaults standardUserDefaults] synchronize]; 353 | } 354 | } 355 | 356 | #pragma mark - Private methods 357 | 358 | - (NSString *)generateUUID { 359 | CFUUIDRef theUUID = CFUUIDCreate(NULL); 360 | CFStringRef string = CFUUIDCreateString(NULL, theUUID); 361 | CFRelease(theUUID); 362 | NSString *res = [(__bridge NSString *)string stringByReplacingOccurrencesOfString:@"-" withString:@""]; 363 | CFRelease(string); 364 | return res; 365 | } 366 | 367 | - (NSDictionary *)prepareDictionaryForMessage:(NSString *)message 368 | level:(RavenLogLevel)level 369 | additionalExtra:(NSDictionary *)additionalExtra 370 | additionalTags:(NSDictionary *)additionalTags 371 | culprit:(NSString *)culprit 372 | stacktrace:(NSArray *)stacktrace 373 | exception:(NSDictionary *)exceptionDict { 374 | NSDictionary *stacktraceDict = [NSDictionary dictionaryWithObjectsAndKeys:stacktrace, @"frames", nil]; 375 | 376 | NSMutableDictionary *extra = [NSMutableDictionary dictionaryWithDictionary:self.extra]; 377 | if (additionalExtra.count) { 378 | [extra addEntriesFromDictionary:additionalExtra]; 379 | } 380 | 381 | NSMutableDictionary *tags = [NSMutableDictionary dictionaryWithDictionary:self.tags]; 382 | if (additionalTags.count) { 383 | [tags addEntriesFromDictionary:additionalTags]; 384 | } 385 | 386 | return [NSDictionary dictionaryWithObjectsAndKeys: 387 | [self generateUUID], @"event_id", 388 | self.config.projectId ?: @"", @"project", 389 | [self.dateFormatter stringFromDate:[NSDate date]], @"timestamp", 390 | kRavenLogLevelArray[level], @"level", 391 | @"objc", @"platform", 392 | self.user ?: @"", @"user", 393 | 394 | extra, @"extra", 395 | tags, @"tags", 396 | self.logger ?: @"", @"logger", 397 | _release ?: @"", @"release", 398 | 399 | message, @"message", 400 | culprit ?: @"", @"culprit", 401 | stacktraceDict, @"stacktrace", 402 | exceptionDict, @"exception", 403 | nil]; 404 | } 405 | 406 | - (void)sendDictionary:(NSDictionary *)dict { 407 | NSData *JSON = [self encodeJSON:dict]; 408 | [self sendJSON:JSON]; 409 | } 410 | 411 | - (void)sendJSON:(NSData *)JSON { 412 | if (!self.config) { 413 | NSLog(@"Sentry JSON (DSN not configured, will not be sent):\n%@\n", 414 | [[NSString alloc] initWithData:JSON encoding:NSUTF8StringEncoding]); 415 | return; 416 | } 417 | 418 | NSString *header = [NSString stringWithFormat:@"Sentry sentry_version=%@, sentry_client=%@, sentry_timestamp=%ld, sentry_key=%@, sentry_secret=%@", 419 | sentryProtocol, 420 | sentryClient, 421 | (long)[NSDate timeIntervalSinceReferenceDate], 422 | self.config.publicKey, 423 | self.config.secretKey]; 424 | 425 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:self.config.serverURL]; 426 | [request setHTTPMethod:@"POST"]; 427 | [request setValue:@"application/json" forHTTPHeaderField:@"Accept"]; 428 | [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; 429 | [request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)[JSON length]] forHTTPHeaderField:@"Content-Length"]; 430 | [request setHTTPBody:JSON]; 431 | [request setValue:header forHTTPHeaderField:@"X-Sentry-Auth"]; 432 | 433 | [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { 434 | if (data) { 435 | NSLog(@"JSON sent to Sentry"); 436 | } else { 437 | NSLog(@"Connection failed! Error - %@ %@", [connectionError localizedDescription], [[connectionError userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]); 438 | } 439 | }]; 440 | } 441 | 442 | #pragma mark - JSON helpers 443 | 444 | - (NSData *)encodeJSON:(id)obj { 445 | NSData *data = [NSJSONSerialization dataWithJSONObject:obj options:0 error:nil]; 446 | return data; 447 | } 448 | 449 | @end 450 | -------------------------------------------------------------------------------- /Raven/RavenClient_Private.h: -------------------------------------------------------------------------------- 1 | // 2 | // RavenClient_Private.h 3 | // Raven 4 | // 5 | // Created by Kevin Renskers on 25-05-12. 6 | // Copyright (c) 2012 Gangverk. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "RavenClient.h" 11 | #import "RavenConfig.h" 12 | 13 | @interface RavenClient () 14 | 15 | @property (strong, nonatomic) NSDateFormatter *dateFormatter; 16 | @property (strong, nonatomic) RavenConfig *config; 17 | 18 | - (NSString *)generateUUID; 19 | - (NSDictionary *)prepareDictionaryForMessage:(NSString *)message 20 | level:(RavenLogLevel)level 21 | additionalExtra:(NSDictionary *)additionalExtra 22 | additionalTags:(NSDictionary *)additionalTags 23 | culprit:(NSString *)culprit 24 | stacktrace:(NSArray *)stacktrace 25 | exception:(NSDictionary *)exceptionDict; 26 | - (void)sendDictionary:(NSDictionary *)dict; 27 | - (void)sendJSON:(NSData *)JSON; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Raven/RavenConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // RavenConfig.h 3 | // Raven 4 | // 5 | // Created by David Cramer on 12/28/12. 6 | // Copyright (c) 2012 Gangverk. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RavenConfig : NSObject 12 | 13 | - (BOOL)setDSN:(NSString *)DSN; 14 | 15 | @property (strong, nonatomic) NSURL *serverURL; 16 | @property (strong, nonatomic) NSString *publicKey; 17 | @property (strong, nonatomic) NSString *secretKey; 18 | @property (strong, nonatomic) NSString *projectId; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Raven/RavenConfig.m: -------------------------------------------------------------------------------- 1 | // 2 | // RavenConfig.m 3 | // Raven 4 | // 5 | // Created by David Cramer on 12/28/12. 6 | // Copyright (c) 2012 Gangverk. All rights reserved. 7 | // 8 | 9 | #import "RavenConfig.h" 10 | 11 | @implementation RavenConfig 12 | 13 | - (BOOL)setDSN:(NSString *)DSN { 14 | NSURL *DSNURL = [NSURL URLWithString:DSN]; 15 | 16 | NSMutableArray *pathComponents = [[DSNURL pathComponents] mutableCopy]; 17 | if (![pathComponents count]) { 18 | NSLog(@"Missing path"); 19 | return NO; 20 | } 21 | 22 | [pathComponents removeObjectAtIndex:0]; // always remove the first slash 23 | 24 | self.projectId = [pathComponents lastObject]; // project id is the last element of the path 25 | 26 | if (!self.projectId) { 27 | return NO; 28 | } 29 | 30 | [pathComponents removeLastObject]; // remove the project id... 31 | NSString *path = [pathComponents componentsJoinedByString:@"/"]; // ...and construct the path again 32 | 33 | // Add a slash to the end of the path if there is a path 34 | if (![path isEqualToString:@""]) { 35 | path = [path stringByAppendingString:@"/"]; 36 | } 37 | 38 | NSNumber *port = [DSNURL port]; 39 | if (!port) { 40 | if ([[DSNURL scheme] isEqualToString:@"https"]) { 41 | port = [NSNumber numberWithInteger:443]; 42 | } else { 43 | port = [NSNumber numberWithInteger:80]; 44 | } 45 | } 46 | 47 | self.serverURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@:%@%@/api/%@/store/", [DSNURL scheme], [DSNURL host], port, path, self.projectId]]; 48 | self.publicKey = [DSNURL user]; 49 | self.secretKey = [DSNURL password]; 50 | 51 | return YES; 52 | } 53 | 54 | 55 | @end 56 | 57 | -------------------------------------------------------------------------------- /RavenTests/RavenClientTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // RavenTests.h 3 | // RavenTests 4 | // 5 | // Created by Kevin Renskers on 25-05-12. 6 | // Copyright (c) 2012 Gangverk. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "RavenClient_Private.h" 11 | 12 | 13 | @interface MockRavenClient : RavenClient 14 | 15 | @property NSDictionary *lastEvent; 16 | @property NSUInteger *numEvents; 17 | 18 | @end 19 | 20 | 21 | @interface RavenClientTest : XCTestCase 22 | 23 | @property MockRavenClient *client; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /RavenTests/RavenClientTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // RavenClientTests.m 3 | // RavenClientTests 4 | // 5 | // Created by David Cramer on 12/28/12. 6 | // Copyright (c) 2012 Gangverk. All rights reserved. 7 | // 8 | 9 | #import "RavenClientTest.h" 10 | 11 | NSString *const testDSN = @"http://public:secret@example.com/foo"; 12 | 13 | @implementation MockRavenClient 14 | 15 | - (void)sendDictionary:(NSDictionary *)dict 16 | { 17 | self.lastEvent = dict; 18 | self.numEvents += 1; 19 | } 20 | 21 | @end 22 | 23 | @implementation RavenClientTest 24 | 25 | - (void)setUp 26 | { 27 | [super setUp]; 28 | 29 | self.client = [[MockRavenClient alloc] initWithDSN:testDSN]; 30 | } 31 | 32 | - (void)tearDown 33 | { 34 | [super tearDown]; 35 | } 36 | 37 | 38 | - (void)testGenerateUUID 39 | { 40 | NSString *uuid = [self.client generateUUID]; 41 | XCTAssertEqual([uuid length], (NSUInteger)32, @"Invalid value for UUID returned: %@", uuid); 42 | } 43 | 44 | - (void)testCaptureMessageWithOnlyMessage 45 | { 46 | [self.client captureMessage:@"An example message"]; 47 | NSDictionary *lastEvent = self.client.lastEvent; 48 | NSArray *keys = [lastEvent allKeys]; 49 | XCTAssertTrue([keys containsObject:@"event_id"], @"Missing event_id"); 50 | XCTAssertTrue([keys containsObject:@"message"], @"Missing message"); 51 | XCTAssertTrue([keys containsObject:@"project"], @"Missing project"); 52 | XCTAssertTrue([keys containsObject:@"level"], @"Missing level"); 53 | XCTAssertTrue([keys containsObject:@"timestamp"], @"Missing timestamp"); 54 | XCTAssertEqual([lastEvent valueForKey:@"message"], @"An example message", 55 | @"Invalid value for message: %@", [lastEvent valueForKey:@"message"]); 56 | XCTAssertEqual([lastEvent valueForKey:@"project"], self.client.config.projectId, 57 | @"Invalid value for project: %@", [lastEvent valueForKey:@"project"]); 58 | XCTAssertTrue([[lastEvent valueForKey:@"level"] isEqualToString:@"info"], 59 | @"Invalid value for level: %@", [lastEvent valueForKey:@"level"]); 60 | } 61 | 62 | - (void)testCaptureMessageWithMessageAndLevel 63 | { 64 | [self.client captureMessage:@"An example message" level:kRavenLogLevelDebugWarning]; 65 | NSDictionary *lastEvent = self.client.lastEvent; 66 | NSArray *keys = [lastEvent allKeys]; 67 | XCTAssertTrue([keys containsObject:@"event_id"], @"Missing event_id"); 68 | XCTAssertTrue([keys containsObject:@"message"], @"Missing message"); 69 | XCTAssertTrue([keys containsObject:@"project"], @"Missing project"); 70 | XCTAssertTrue([keys containsObject:@"level"], @"Missing level"); 71 | XCTAssertTrue([keys containsObject:@"timestamp"], @"Missing timestamp"); 72 | XCTAssertTrue([keys containsObject:@"platform"], @"Missing platform"); 73 | XCTAssertEqual([lastEvent valueForKey:@"message"], @"An example message", 74 | @"Invalid value for message: %@", [lastEvent valueForKey:@"message"]); 75 | XCTAssertEqual([lastEvent valueForKey:@"project"], self.client.config.projectId, 76 | @"Invalid value for project: %@", [lastEvent valueForKey:@"project"]); 77 | XCTAssertTrue([[lastEvent valueForKey:@"level"] isEqualToString:@"warning"], 78 | @"Invalid value for level: %@", [lastEvent valueForKey:@"level"]); 79 | XCTAssertEqual([lastEvent valueForKey:@"platform"], @"objc", 80 | @"Invalid value for platform: %@", [lastEvent valueForKey:@"platform"]); 81 | } 82 | 83 | 84 | - (void)testCaptureMessageWithMessageAndLevelAndMethodAndFileAndLine 85 | { 86 | [self.client captureMessage:@"An example message" level:kRavenLogLevelDebugWarning 87 | method:"method name" file:"filename" line:34]; 88 | NSDictionary *lastEvent = self.client.lastEvent; 89 | NSArray *keys = [lastEvent allKeys]; 90 | XCTAssertTrue([keys containsObject:@"event_id"], @"Missing event_id"); 91 | XCTAssertTrue([keys containsObject:@"message"], @"Missing message"); 92 | XCTAssertTrue([keys containsObject:@"project"], @"Missing project"); 93 | XCTAssertTrue([keys containsObject:@"level"], @"Missing level"); 94 | XCTAssertTrue([keys containsObject:@"timestamp"], @"Missing timestamp"); 95 | XCTAssertTrue([keys containsObject:@"platform"], @"Missing platform"); 96 | XCTAssertTrue([keys containsObject:@"stacktrace"], @"Missing stacktrace"); 97 | XCTAssertEqual([lastEvent valueForKey:@"message"], @"An example message", 98 | @"Invalid value for message: %@", [lastEvent valueForKey:@"message"]); 99 | XCTAssertEqual([lastEvent valueForKey:@"project"], self.client.config.projectId, 100 | @"Invalid value for project: %@", [lastEvent valueForKey:@"project"]); 101 | XCTAssertTrue([[lastEvent valueForKey:@"level"] isEqualToString:@"warning"], 102 | @"Invalid value for level: %@", [lastEvent valueForKey:@"level"]); 103 | XCTAssertEqual([lastEvent valueForKey:@"platform"], @"objc", 104 | @"Invalid value for platform: %@", [lastEvent valueForKey:@"platform"]); 105 | } 106 | 107 | 108 | - (void)testCaptureMessageWithMessageAndLevelAndStacktrace 109 | { 110 | NSDictionary *frame = [NSDictionary dictionaryWithObjectsAndKeys:@"method name", @"method", @"filename", @"file", @34, @"line", nil]; 111 | NSArray *stacktrace = [NSArray arrayWithObjects:frame, nil]; 112 | [self.client captureMessage:@"An example message" level:kRavenLogLevelDebugWarning additionalExtra:nil additionalTags:nil stacktrace:stacktrace culprit:nil sendNow:YES]; 113 | 114 | NSDictionary *lastEvent = self.client.lastEvent; 115 | NSArray *keys = [lastEvent allKeys]; 116 | XCTAssertTrue([keys containsObject:@"event_id"], @"Missing event_id"); 117 | XCTAssertTrue([keys containsObject:@"message"], @"Missing message"); 118 | XCTAssertTrue([keys containsObject:@"project"], @"Missing project"); 119 | XCTAssertTrue([keys containsObject:@"level"], @"Missing level"); 120 | XCTAssertTrue([keys containsObject:@"timestamp"], @"Missing timestamp"); 121 | XCTAssertTrue([keys containsObject:@"platform"], @"Missing platform"); 122 | XCTAssertTrue([keys containsObject:@"stacktrace"], @"Missing stacktrace"); 123 | XCTAssertEqual([lastEvent valueForKey:@"message"], @"An example message", 124 | @"Invalid value for message: %@", [lastEvent valueForKey:@"message"]); 125 | XCTAssertEqual([lastEvent valueForKey:@"project"], self.client.config.projectId, 126 | @"Invalid value for project: %@", [lastEvent valueForKey:@"project"]); 127 | XCTAssertTrue([[lastEvent valueForKey:@"level"] isEqualToString:@"warning"], 128 | @"Invalid value for level: %@", [lastEvent valueForKey:@"level"]); 129 | XCTAssertEqual([lastEvent valueForKey:@"platform"], @"objc", 130 | @"Invalid value for platform: %@", [lastEvent valueForKey:@"platform"]); 131 | } 132 | 133 | - (void)testCaptureMessageWithMessageAndLevelAndExtraAndTags 134 | { 135 | [self.client captureMessage:@"An example message" 136 | level:kRavenLogLevelDebugWarning 137 | additionalExtra:@{@"key" : @"extra value"} 138 | additionalTags:@{@"key" : @"tag value"}]; 139 | 140 | NSDictionary *lastEvent = self.client.lastEvent; 141 | NSArray *keys = [lastEvent allKeys]; 142 | XCTAssertTrue([keys containsObject:@"event_id"], @"Missing event_id"); 143 | XCTAssertTrue([keys containsObject:@"message"], @"Missing message"); 144 | XCTAssertTrue([keys containsObject:@"project"], @"Missing project"); 145 | XCTAssertTrue([keys containsObject:@"level"], @"Missing level"); 146 | XCTAssertTrue([keys containsObject:@"timestamp"], @"Missing timestamp"); 147 | XCTAssertTrue([keys containsObject:@"platform"], @"Missing platform"); 148 | XCTAssertTrue([keys containsObject:@"extra"], @"Missing extra"); 149 | XCTAssertTrue([keys containsObject:@"tags"], @"Missing tags"); 150 | 151 | XCTAssertEqual([lastEvent[@"extra"] objectForKey:@"key"], @"extra value", @"Missing extra data"); 152 | XCTAssertEqual([lastEvent[@"tags"] objectForKey:@"key"], @"tag value", @"Missing tags data"); 153 | 154 | XCTAssertEqual([lastEvent valueForKey:@"message"], @"An example message", 155 | @"Invalid value for message: %@", [lastEvent valueForKey:@"message"]); 156 | XCTAssertEqual([lastEvent valueForKey:@"project"], self.client.config.projectId, 157 | @"Invalid value for project: %@", [lastEvent valueForKey:@"project"]); 158 | XCTAssertTrue([[lastEvent valueForKey:@"level"] isEqualToString:@"warning"], 159 | @"Invalid value for level: %@", [lastEvent valueForKey:@"level"]); 160 | XCTAssertEqual([lastEvent valueForKey:@"platform"], @"objc", 161 | @"Invalid value for platform: %@", [lastEvent valueForKey:@"platform"]); 162 | } 163 | 164 | - (void)testClientWithExtraAndTags 165 | { 166 | NSDictionary *extra = @{@"key" : @"value"}; 167 | NSDictionary *tags = @{@"key" : @"value"}; 168 | 169 | MockRavenClient *client = [[MockRavenClient alloc] initWithDSN:testDSN extra:extra tags:tags]; 170 | [client captureMessage:@"An example message" 171 | level:kRavenLogLevelDebugWarning 172 | additionalExtra:@{@"key2" : @"extra value"} 173 | additionalTags:@{@"key2" : @"tag value"}]; 174 | 175 | NSDictionary *lastEvent = client.lastEvent; 176 | NSArray *keys = [lastEvent allKeys]; 177 | 178 | XCTAssertTrue([keys containsObject:@"extra"], @"Missing extra"); 179 | XCTAssertTrue([keys containsObject:@"tags"], @"Missing tags"); 180 | XCTAssertEqual([lastEvent[@"extra"] objectForKey:@"key"], @"value", @"Missing extra data"); 181 | XCTAssertEqual([lastEvent[@"tags"] objectForKey:@"key"], @"value", @"Missing tags data"); 182 | 183 | XCTAssertEqual([lastEvent[@"extra"] objectForKey:@"key2"], @"extra value", @"Missing extra data"); 184 | XCTAssertEqual([lastEvent[@"tags"] objectForKey:@"key2"], @"tag value", @"Missing tags data"); 185 | 186 | XCTAssertNotNil([lastEvent[@"tags"] objectForKey:@"OS version"], @"Missing tags data"); 187 | XCTAssertNotNil([lastEvent[@"tags"] objectForKey:@"Device model"], @"Missing tags data"); 188 | } 189 | 190 | - (void)testClientWithRewritingExtraAndTags 191 | { 192 | NSDictionary *extra = @{@"key" : @"value"}; 193 | NSDictionary *tags = @{@"key" : @"value"}; 194 | 195 | MockRavenClient *client = [[MockRavenClient alloc] initWithDSN:testDSN extra:extra tags:tags]; 196 | [client captureMessage:@"An example message" 197 | level:kRavenLogLevelDebugWarning 198 | additionalExtra:@{@"key" : @"extra value"} 199 | additionalTags:@{@"key" : @"tag value"}]; 200 | 201 | NSDictionary *lastEvent = client.lastEvent; 202 | NSArray *keys = [lastEvent allKeys]; 203 | 204 | XCTAssertTrue([keys containsObject:@"extra"], @"Missing extra"); 205 | XCTAssertTrue([keys containsObject:@"tags"], @"Missing tags"); 206 | 207 | XCTAssertEqual([lastEvent[@"extra"] objectForKey:@"key"], @"extra value", @"Missing extra data"); 208 | XCTAssertEqual([lastEvent[@"tags"] objectForKey:@"key"], @"tag value", @"Missing tags data"); 209 | } 210 | 211 | - (void)testClientWithLogger 212 | { 213 | NSDictionary *extra = @{@"key" : @"value"}; 214 | NSDictionary *tags = @{@"key" : @"value"}; 215 | NSString *logger = @"Logger value"; 216 | 217 | MockRavenClient *client = [[MockRavenClient alloc] initWithDSN:testDSN extra:extra tags:tags logger:logger]; 218 | [client captureMessage:@"An example message"]; 219 | 220 | NSDictionary *lastEvent = client.lastEvent; 221 | 222 | XCTAssertEqual([lastEvent valueForKey:@"message"], @"An example message", 223 | @"Invalid value for message: %@", [lastEvent valueForKey:@"message"]); 224 | XCTAssertEqual([lastEvent valueForKey:@"logger"], @"Logger value", 225 | @"Invalid value for logger: %@", [lastEvent valueForKey:@"logger"]); 226 | 227 | } 228 | 229 | - (void)testClientWithUser 230 | { 231 | MockRavenClient *client = [[MockRavenClient alloc] initWithDSN:testDSN]; 232 | client.user = @{@"username" : @"timor", @"ip_address" : @"127.0.0.1"}; 233 | [client captureMessage:@"An example message"]; 234 | 235 | NSDictionary *lastEvent = client.lastEvent; 236 | 237 | NSArray *keys = [lastEvent allKeys]; 238 | XCTAssertTrue([keys containsObject:@"user"], @"Missing user"); 239 | 240 | XCTAssertEqual([lastEvent[@"user"] objectForKey:@"username"], @"timor", @"Missing username"); 241 | XCTAssertEqual([lastEvent[@"user"] objectForKey:@"ip_address"], @"127.0.0.1", @"Missing ip address"); 242 | 243 | XCTAssertEqual([lastEvent valueForKey:@"message"], @"An example message", 244 | @"Invalid value for message: %@", [lastEvent valueForKey:@"message"]); 245 | } 246 | 247 | - (void)testClientWithoutDSN 248 | { 249 | MockRavenClient *client = [[MockRavenClient alloc] initWithDSN:nil]; 250 | client.user = @{@"username" : @"timor", @"ip_address" : @"127.0.0.1"}; 251 | 252 | [client captureMessage:@"An example message"]; 253 | 254 | NSDictionary *lastEvent = client.lastEvent; 255 | 256 | NSArray *keys = [lastEvent allKeys]; 257 | XCTAssertTrue([keys containsObject:@"user"], @"Missing user"); 258 | 259 | XCTAssertEqual([lastEvent[@"user"] objectForKey:@"username"], @"timor", @"Missing username"); 260 | XCTAssertEqual([lastEvent[@"user"] objectForKey:@"ip_address"], @"127.0.0.1", @"Missing ip address"); 261 | 262 | XCTAssertEqual([lastEvent valueForKey:@"message"], @"An example message", 263 | @"Invalid value for message: %@", [lastEvent valueForKey:@"message"]); 264 | } 265 | 266 | - (void)testClientWithEmptyRelease 267 | { 268 | MockRavenClient *client = [[MockRavenClient alloc] initWithDSN:testDSN]; 269 | [client captureMessage:@"An example message"]; 270 | 271 | NSDictionary *lastEvent = client.lastEvent; 272 | 273 | XCTAssertEqual([lastEvent valueForKey:@"release"], @"", 274 | @"Invalid value for release: %@", [lastEvent valueForKey:@"release"]); 275 | 276 | } 277 | 278 | - (void)testClientWithExplicitRelease 279 | { 280 | MockRavenClient *client = [[MockRavenClient alloc] initWithDSN:testDSN]; 281 | 282 | [client setRelease:@"1.0"]; 283 | 284 | [client captureMessage:@"An example message"]; 285 | 286 | NSDictionary *lastEvent = client.lastEvent; 287 | 288 | XCTAssertEqual([lastEvent valueForKey:@"release"], @"1.0", 289 | @"Invalid value for release: %@", [lastEvent valueForKey:@"release"]); 290 | 291 | } 292 | 293 | @end 294 | -------------------------------------------------------------------------------- /RavenTests/RavenConfigTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // RavenConfigTest.h 3 | // Raven 4 | // 5 | // Created by David Cramer on 12/28/12. 6 | // Copyright (c) 2012 Gangverk. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RavenConfigTest : XCTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /RavenTests/RavenConfigTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // RavenConfigTest.m 3 | // Raven 4 | // 5 | // Created by David Cramer on 12/28/12. 6 | // Copyright (c) 2012 Gangverk. All rights reserved. 7 | // 8 | 9 | #import "RavenConfigTest.h" 10 | #import "RavenConfig.h" 11 | 12 | @implementation RavenConfigTest 13 | 14 | - (void)testSetDSNWithPort 15 | { 16 | RavenConfig *config = [RavenConfig alloc]; 17 | BOOL didParse = [config setDSN:@"http://public_key:secret_key@example.com:8000/project-id"]; 18 | 19 | XCTAssertTrue(didParse, @"Failed to parse DSN"); 20 | 21 | XCTAssertTrue([config.publicKey isEqualToString:@"public_key"], @"Got incorrect publicKey %@", config.publicKey); 22 | XCTAssertTrue([config.secretKey isEqualToString:@"secret_key"], @"Got incorrect secretKey %@", config.secretKey); 23 | XCTAssertTrue([config.projectId isEqualToString:@"project-id"], @"Got incorrect projectId %@", config.projectId); 24 | 25 | NSString *expectedURL = @"http://example.com:8000/api/project-id/store/"; 26 | 27 | XCTAssertTrue([[config.serverURL absoluteString] isEqualToString:expectedURL], @"Got incorrect serverURL %@", [config.serverURL absoluteString]); 28 | } 29 | 30 | - (void)testSetDSNWithSSLPortUndefined 31 | { 32 | RavenConfig *config = [RavenConfig alloc]; 33 | BOOL didParse = [config setDSN:@"https://public_key:secret_key@example.com/project-id"]; 34 | 35 | XCTAssertTrue(didParse, @"Failed to parse DSN"); 36 | 37 | XCTAssertTrue([config.publicKey isEqualToString:@"public_key"], @"Got incorrect publicKey %@", config.publicKey); 38 | XCTAssertTrue([config.secretKey isEqualToString:@"secret_key"], @"Got incorrect secretKey %@", config.secretKey); 39 | XCTAssertTrue([config.projectId isEqualToString:@"project-id"], @"Got incorrect projectId %@", config.projectId); 40 | 41 | NSString *expectedURL = @"https://example.com:443/api/project-id/store/"; 42 | 43 | XCTAssertTrue([[config.serverURL absoluteString] isEqualToString:expectedURL], @"Got incorrect serverURL %@", [config.serverURL absoluteString]); 44 | } 45 | 46 | - (void)testSetDSNWithoutSSLPortUndefined 47 | { 48 | RavenConfig *config = [RavenConfig alloc]; 49 | BOOL didParse = [config setDSN:@"http://public_key:secret_key@example.com/project-id"]; 50 | 51 | XCTAssertTrue(didParse, @"Failed to parse DSN"); 52 | 53 | XCTAssertTrue([config.publicKey isEqualToString:@"public_key"], @"Got incorrect publicKey %@", config.publicKey); 54 | XCTAssertTrue([config.secretKey isEqualToString:@"secret_key"], @"Got incorrect secretKey %@", config.secretKey); 55 | XCTAssertTrue([config.projectId isEqualToString:@"project-id"], @"Got incorrect projectId %@", config.projectId); 56 | 57 | NSString *expectedURL = @"http://example.com:80/api/project-id/store/"; 58 | 59 | XCTAssertTrue([[config.serverURL absoluteString] isEqualToString:expectedURL], @"Got incorrect serverURL %@", [config.serverURL absoluteString]); 60 | } 61 | 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /RavenTests/RavenTests-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 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /RavenTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /bin/test: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | FLAGS="-scheme RavenTests -target RavenTests -sdk iphonesimulator" 4 | 5 | if [ -e $(which xcpretty) ]; then 6 | xcodebuild $FLAGS test | xcpretty --color 7 | else 8 | xcodebuild $FLAGS test 9 | fi 10 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 18 | 19 | help: 20 | @echo "Please use \`make ' where is one of" 21 | @echo " html to make standalone HTML files" 22 | @echo " dirhtml to make HTML files named index.html in directories" 23 | @echo " singlehtml to make a single large HTML file" 24 | @echo " pickle to make pickle files" 25 | @echo " json to make JSON files" 26 | @echo " htmlhelp to make HTML files and a HTML help project" 27 | @echo " qthelp to make HTML files and a qthelp project" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 31 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 32 | @echo " text to make text files" 33 | @echo " man to make manual pages" 34 | @echo " texinfo to make Texinfo files" 35 | @echo " info to make Texinfo files and run them through makeinfo" 36 | @echo " gettext to make PO message catalogs" 37 | @echo " changes to make an overview of all changed/added/deprecated items" 38 | @echo " linkcheck to check all external links for integrity" 39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 40 | 41 | clean: 42 | -rm -rf $(BUILDDIR)/* 43 | 44 | html: 45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 48 | 49 | dirhtml: 50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 51 | @echo 52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 53 | 54 | singlehtml: 55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 56 | @echo 57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 58 | 59 | pickle: 60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 61 | @echo 62 | @echo "Build finished; now you can process the pickle files." 63 | 64 | json: 65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 66 | @echo 67 | @echo "Build finished; now you can process the JSON files." 68 | 69 | htmlhelp: 70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 71 | @echo 72 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 73 | ".hhp project file in $(BUILDDIR)/htmlhelp." 74 | 75 | qthelp: 76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 77 | @echo 78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/raven-js.qhcp" 81 | @echo "To view the help file:" 82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/raven-js.qhc" 83 | 84 | devhelp: 85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 86 | @echo 87 | @echo "Build finished." 88 | @echo "To view the help file:" 89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/raven-js" 90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/raven-js" 91 | @echo "# devhelp" 92 | 93 | epub: 94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 95 | @echo 96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 97 | 98 | latex: 99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 100 | @echo 101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 103 | "(use \`make latexpdf' here to do that automatically)." 104 | 105 | latexpdf: 106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 107 | @echo "Running LaTeX files through pdflatex..." 108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 110 | 111 | text: 112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 113 | @echo 114 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 115 | 116 | man: 117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 118 | @echo 119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 120 | 121 | texinfo: 122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 123 | @echo 124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 125 | @echo "Run \`make' in that directory to run these through makeinfo" \ 126 | "(use \`make info' here to do that automatically)." 127 | 128 | info: 129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 130 | @echo "Running Texinfo files through makeinfo..." 131 | make -C $(BUILDDIR)/texinfo info 132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 133 | 134 | gettext: 135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 136 | @echo 137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 138 | 139 | changes: 140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 141 | @echo 142 | @echo "The overview file is in $(BUILDDIR)/changes." 143 | 144 | linkcheck: 145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 146 | @echo 147 | @echo "Link check complete; look for any errors in the above output " \ 148 | "or in $(BUILDDIR)/linkcheck/output.txt." 149 | 150 | doctest: 151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 152 | @echo "Testing of doctests in the sources finished, look at the " \ 153 | "results in $(BUILDDIR)/doctest/output.txt." 154 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # raven-objc documentation build configuration file, created by 4 | # sphinx-quickstart on Mon Jan 21 21:04:27 2013. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os, datetime, re 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | #sys.path.insert(0, os.path.abspath('.')) 20 | 21 | # -- General configuration ----------------------------------------------------- 22 | 23 | # If your documentation needs a minimal Sphinx version, state it here. 24 | #needs_sphinx = '1.0' 25 | 26 | # Add any Sphinx extension module names here, as strings. They can be extensions 27 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 28 | extensions = [] 29 | 30 | # Add any paths that contain templates here, relative to this directory. 31 | templates_path = ['_templates'] 32 | 33 | # The suffix of source filenames. 34 | source_suffix = '.rst' 35 | 36 | # The encoding of source files. 37 | #source_encoding = 'utf-8-sig' 38 | 39 | # The master toctree document. 40 | master_doc = 'index' 41 | 42 | # General information about the project. 43 | project = u'raven-objc' 44 | copyright = u'%s, Functional Software Inc.' % datetime.date.today().year 45 | 46 | # The version info for the project you're documenting, acts as replacement for 47 | # |version| and |release|, also used in various other places throughout the 48 | # built documents. 49 | # 50 | 51 | # The full version, including alpha/beta/rc tags. 52 | with open('../Raven.podspec') as f: 53 | release = re.search(r's.version\s*=\s*"(.*?)"', f.read()).group(1) 54 | # The short X.Y version. 55 | version = release.rsplit('.', 1)[0] 56 | 57 | # The language for content autogenerated by Sphinx. Refer to documentation 58 | # for a list of supported languages. 59 | #language = None 60 | 61 | # There are two options for replacing |today|: either, you set today to some 62 | # non-false value, then it is used: 63 | #today = '' 64 | # Else, today_fmt is used as the format for a strftime call. 65 | #today_fmt = '%B %d, %Y' 66 | 67 | # List of patterns, relative to source directory, that match files and 68 | # directories to ignore when looking for source files. 69 | exclude_patterns = ['_build'] 70 | 71 | # The reST default role (used for this markup: `text`) to use for all documents. 72 | #default_role = None 73 | 74 | # If true, '()' will be appended to :func: etc. cross-reference text. 75 | #add_function_parentheses = True 76 | 77 | # If true, the current module name will be prepended to all description 78 | # unit titles (such as .. function::). 79 | #add_module_names = True 80 | 81 | # If true, sectionauthor and moduleauthor directives will be shown in the 82 | # output. They are ignored by default. 83 | #show_authors = False 84 | 85 | # The name of the Pygments (syntax highlighting) style to use. 86 | pygments_style = 'sphinx' 87 | 88 | # A list of ignored prefixes for module index sorting. 89 | #modindex_common_prefix = [] 90 | 91 | 92 | # -- Options for HTML output --------------------------------------------------- 93 | 94 | # The theme to use for HTML and HTML Help pages. See the documentation for 95 | # a list of builtin themes. 96 | html_theme = 'default' 97 | 98 | # Theme options are theme-specific and customize the look and feel of a theme 99 | # further. For a list of options available for each theme, see the 100 | # documentation. 101 | #html_theme_options = {} 102 | 103 | # Add any paths that contain custom themes here, relative to this directory. 104 | #html_theme_path = [] 105 | 106 | # The name for this set of Sphinx documents. If None, it defaults to 107 | # " v documentation". 108 | #html_title = None 109 | 110 | # A shorter title for the navigation bar. Default is the same as html_title. 111 | #html_short_title = None 112 | 113 | # The name of an image file (relative to this directory) to place at the top 114 | # of the sidebar. 115 | #html_logo = None 116 | 117 | # The name of an image file (within the static path) to use as favicon of the 118 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 119 | # pixels large. 120 | #html_favicon = None 121 | 122 | # Add any paths that contain custom static files (such as style sheets) here, 123 | # relative to this directory. They are copied after the builtin static files, 124 | # so a file named "default.css" will overwrite the builtin "default.css". 125 | #html_static_path = ['_static'] 126 | 127 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 128 | # using the given strftime format. 129 | #html_last_updated_fmt = '%b %d, %Y' 130 | 131 | # If true, SmartyPants will be used to convert quotes and dashes to 132 | # typographically correct entities. 133 | #html_use_smartypants = True 134 | 135 | # Custom sidebar templates, maps document names to template names. 136 | #html_sidebars = {} 137 | 138 | # Additional templates that should be rendered to pages, maps page names to 139 | # template names. 140 | #html_additional_pages = {} 141 | 142 | # If false, no module index is generated. 143 | #html_domain_indices = True 144 | 145 | # If false, no index is generated. 146 | #html_use_index = True 147 | 148 | # If true, the index is split into individual pages for each letter. 149 | #html_split_index = False 150 | 151 | # If true, links to the reST sources are added to the pages. 152 | #html_show_sourcelink = True 153 | 154 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 155 | #html_show_sphinx = True 156 | 157 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 158 | #html_show_copyright = True 159 | 160 | # If true, an OpenSearch description file will be output, and all pages will 161 | # contain a tag referring to it. The value of this option must be the 162 | # base URL from which the finished HTML is served. 163 | #html_use_opensearch = '' 164 | 165 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 166 | #html_file_suffix = None 167 | 168 | # Output file base name for HTML help builder. 169 | htmlhelp_basename = 'raven-objcdoc' 170 | 171 | 172 | # -- Options for LaTeX output -------------------------------------------------- 173 | 174 | latex_elements = { 175 | # The paper size ('letterpaper' or 'a4paper'). 176 | #'papersize': 'letterpaper', 177 | 178 | # The font size ('10pt', '11pt' or '12pt'). 179 | #'pointsize': '10pt', 180 | 181 | # Additional stuff for the LaTeX preamble. 182 | #'preamble': '', 183 | } 184 | 185 | # Grouping the document tree into LaTeX files. List of tuples 186 | # (source start file, target name, title, author, documentclass [howto/manual]). 187 | latex_documents = [ 188 | ('index', 'raven-objc.tex', u'raven-objc Documentation', 189 | u'Functional Software Inc.', 'manual'), 190 | ] 191 | 192 | # The name of an image file (relative to this directory) to place at the top of 193 | # the title page. 194 | #latex_logo = None 195 | 196 | # For "manual" documents, if this is true, then toplevel headings are parts, 197 | # not chapters. 198 | #latex_use_parts = False 199 | 200 | # If true, show page references after internal links. 201 | #latex_show_pagerefs = False 202 | 203 | # If true, show URL addresses after external links. 204 | #latex_show_urls = False 205 | 206 | # Documents to append as an appendix to all manuals. 207 | #latex_appendices = [] 208 | 209 | # If false, no module index is generated. 210 | #latex_domain_indices = True 211 | 212 | 213 | # -- Options for manual page output -------------------------------------------- 214 | 215 | # One entry per manual page. List of tuples 216 | # (source start file, name, description, authors, manual section). 217 | man_pages = [ 218 | ('index', 'raven-objc', u'raven-objc Documentation', 219 | [u'Functional Software Inc.'], 1) 220 | ] 221 | 222 | # If true, show URL addresses after external links. 223 | #man_show_urls = False 224 | 225 | 226 | # -- Options for Texinfo output ------------------------------------------------ 227 | 228 | # Grouping the document tree into Texinfo files. List of tuples 229 | # (source start file, target name, title, author, 230 | # dir menu entry, description, category) 231 | texinfo_documents = [ 232 | ('index', 'raven-objc', u'raven-objc Documentation', 233 | u'Functional Software Inc.', 'raven-objc', 'One line description of project.', 234 | 'Miscellaneous'), 235 | ] 236 | 237 | # Documents to append as an appendix to all manuals. 238 | #texinfo_appendices = [] 239 | 240 | # If false, no module index is generated. 241 | #texinfo_domain_indices = True 242 | 243 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 244 | #texinfo_show_urls = 'footnote' 245 | 246 | if os.environ.get('SENTRY_FEDERATED_DOCS') != '1': 247 | sys.path.insert(0, os.path.abspath('_sentryext')) 248 | import sentryext 249 | sentryext.activate() 250 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. sentry:edition:: self 2 | 3 | Raven-Objc 4 | ========== 5 | 6 | .. sentry:edition:: on-premise, hosted 7 | 8 | .. class:: platform-objc 9 | 10 | Objective-C 11 | =========== 12 | 13 | .. sentry:support-warning:: 14 | 15 | The Objective-C SDK is maintained and supported by the Sentry 16 | community. Learn more about the project on `GitHub 17 | `__. 18 | 19 | 20 | The Objective-C client (raven-objc) allows the submission of information 21 | to Sentry from Objective-C applications. 22 | 23 | Installation 24 | ------------ 25 | 26 | The easiest way is to use `CocoaPods`_. It takes care of all required 27 | frameworks and third party dependencies:: 28 | 29 | $ pod 'Raven' 30 | 31 | Alternatively, you can install manually. 32 | 33 | 1. Get the code:: 34 | 35 | git clone git://github.com/getsentry/raven-objc 36 | 37 | 2. Drag the ``Raven`` subfolder to your project. Check both "copy items into 38 | destination group's folder" and your target. 39 | 40 | Alternatively you can add this code as a Git submodule: 41 | 42 | 1. Execute the following commands:: 43 | 44 | cd [your project root] 45 | git submodule add git://github.com/getsentry/raven-objc 46 | 47 | 2. Drag the ``Raven`` subfolder to your project. Uncheck the "copy items into 48 | destination group's folder" box, do check your target. 49 | 50 | Configuration 51 | ------------- 52 | 53 | While you are free to initialize as many instances of ``RavenClient`` as 54 | is appropriate for your application, there is a shared singleton instance 55 | that is globally available. This singleton instance is often configured in 56 | your app delegate's ``application:didFinishLaunchingWithOptions:`` 57 | method: 58 | 59 | .. sourcecode:: objc 60 | 61 | #import "RavenClient.h" 62 | 63 | - (BOOL)application:(UIApplication *)application 64 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 65 | RavenClient *client = [RavenClient clientWithDSN:@"___DSN___"]; 66 | /* ... */ 67 | return YES; 68 | } 69 | 70 | If you do not want to send to Sentry in debug builds, you can configure 71 | ``RavenClient`` without a DSN: 72 | 73 | .. sourcecode:: objc 74 | 75 | RavenClient *client = [RavenClient clientWithDSN:nil]; 76 | 77 | The client will output the data as JSON, but not send anything to Sentry. 78 | 79 | If you would like to use the singleton pattern, you can set the shared 80 | client that is used with the ``+[setSharedClient:]`` class method. After 81 | setting a client, you can retreive the singleton instance via the 82 | ``sharedClient`` singleton method: 83 | 84 | .. sourcecode:: objc 85 | 86 | [RavenClient setSharedClient:client]; 87 | NSLog(@"I am your RavenClient singleton: %@", [RavenClient sharedClient]); 88 | 89 | 90 | .. _CocoaPods: http://cocoapods.org/ 91 | 92 | Sending Messages 93 | ---------------- 94 | 95 | Sending a basic message (note, does not include a stacktrace): 96 | 97 | .. sourcecode:: objc 98 | 99 | [[RavenClient sharedClient] captureMessage:@"TEST 1 2 3"]; 100 | 101 | Sending a message with another level and a stacktrace: 102 | 103 | .. sourcecode:: objc 104 | 105 | [[RavenClient sharedClient] captureMessage:@"TEST 1 2 3" 106 | level:kRavenLogLevelDebugInfo method:__FUNCTION__ file:__FILE__ 107 | line:__LINE__]; 108 | 109 | Recommended macro to send a message with automatic stacktrace: 110 | 111 | .. sourcecode:: objc 112 | 113 | RavenCaptureMessage(@"TEST %i %@ %f", 1, @"2", 3.0); 114 | 115 | Handling Exceptions 116 | ------------------- 117 | 118 | Setup a global exception handler (only iOS): 119 | 120 | .. sourcecode:: objc 121 | 122 | - (BOOL)application:(UIApplication *)application 123 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 124 | RavenClient *client = [RavenClient clientWithDSN:@"___DSN___"]; 125 | [client setupExceptionHandler]; 126 | /* ... */ 127 | return YES; 128 | } 129 | 130 | Or, capture a single exception: 131 | 132 | .. sourcecode:: objc 133 | 134 | @try { 135 | [self performSelector:@selector(nonExistingSelector)]; 136 | } 137 | @catch (NSException *exception) { 138 | RavenCaptureException(exception); 139 | } 140 | 141 | You can also capture errors: 142 | 143 | .. sourcecode:: objc 144 | 145 | NSError *error; 146 | [[NSFileManager defaultManager] removeItemAtPath:@"some/path" error:&error]; 147 | RavenCaptureError(error); 148 | 149 | .. note:: when using the global exception handler, exceptions will be sent 150 | the next time the app is started. 151 | 152 | ARC Support 153 | ----------- 154 | 155 | raven-objc requires ARC support and should run on iOS 5.0 and Mac OS X 156 | 10.7. 157 | 158 | Resources 159 | --------- 160 | 161 | * `Bug Tracker `_ 162 | * `Github Project `_ 163 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. linkcheck to check all external links for integrity 37 | echo. doctest to run all doctests embedded in the documentation if enabled 38 | goto end 39 | ) 40 | 41 | if "%1" == "clean" ( 42 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 43 | del /q /s %BUILDDIR%\* 44 | goto end 45 | ) 46 | 47 | if "%1" == "html" ( 48 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 49 | if errorlevel 1 exit /b 1 50 | echo. 51 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 52 | goto end 53 | ) 54 | 55 | if "%1" == "dirhtml" ( 56 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 57 | if errorlevel 1 exit /b 1 58 | echo. 59 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 60 | goto end 61 | ) 62 | 63 | if "%1" == "singlehtml" ( 64 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 68 | goto end 69 | ) 70 | 71 | if "%1" == "pickle" ( 72 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished; now you can process the pickle files. 76 | goto end 77 | ) 78 | 79 | if "%1" == "json" ( 80 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished; now you can process the JSON files. 84 | goto end 85 | ) 86 | 87 | if "%1" == "htmlhelp" ( 88 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can run HTML Help Workshop with the ^ 92 | .hhp project file in %BUILDDIR%/htmlhelp. 93 | goto end 94 | ) 95 | 96 | if "%1" == "qthelp" ( 97 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 98 | if errorlevel 1 exit /b 1 99 | echo. 100 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 101 | .qhcp project file in %BUILDDIR%/qthelp, like this: 102 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\raven-js.qhcp 103 | echo.To view the help file: 104 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\raven-js.ghc 105 | goto end 106 | ) 107 | 108 | if "%1" == "devhelp" ( 109 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 110 | if errorlevel 1 exit /b 1 111 | echo. 112 | echo.Build finished. 113 | goto end 114 | ) 115 | 116 | if "%1" == "epub" ( 117 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 118 | if errorlevel 1 exit /b 1 119 | echo. 120 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 121 | goto end 122 | ) 123 | 124 | if "%1" == "latex" ( 125 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 129 | goto end 130 | ) 131 | 132 | if "%1" == "text" ( 133 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The text files are in %BUILDDIR%/text. 137 | goto end 138 | ) 139 | 140 | if "%1" == "man" ( 141 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 145 | goto end 146 | ) 147 | 148 | if "%1" == "texinfo" ( 149 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 150 | if errorlevel 1 exit /b 1 151 | echo. 152 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 153 | goto end 154 | ) 155 | 156 | if "%1" == "gettext" ( 157 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 158 | if errorlevel 1 exit /b 1 159 | echo. 160 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 161 | goto end 162 | ) 163 | 164 | if "%1" == "changes" ( 165 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 166 | if errorlevel 1 exit /b 1 167 | echo. 168 | echo.The overview file is in %BUILDDIR%/changes. 169 | goto end 170 | ) 171 | 172 | if "%1" == "linkcheck" ( 173 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 174 | if errorlevel 1 exit /b 1 175 | echo. 176 | echo.Link check complete; look for any errors in the above output ^ 177 | or in %BUILDDIR%/linkcheck/output.txt. 178 | goto end 179 | ) 180 | 181 | if "%1" == "doctest" ( 182 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 183 | if errorlevel 1 exit /b 1 184 | echo. 185 | echo.Testing of doctests in the sources finished, look at the ^ 186 | results in %BUILDDIR%/doctest/output.txt. 187 | goto end 188 | ) 189 | 190 | :end 191 | -------------------------------------------------------------------------------- /docs/sentry-doc-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "support_level": "community", 3 | "platforms": { 4 | "objc": { 5 | "name": "Objective-C", 6 | "type": "language", 7 | "doc_link": "", 8 | "wizard": [ 9 | "index#installation", 10 | "index#configuration", 11 | "index#handling-exceptions" 12 | ] 13 | } 14 | } 15 | } 16 | --------------------------------------------------------------------------------