Skip to content
Browse files

Sub in NWHandy.

  • Loading branch information...
1 parent cac9a29 commit a0b4badf775dd3e5546f13ae7a8ce4ab817b7d97 @nolanw committed Feb 12, 2011
View
6 Credits.markdown
@@ -4,13 +4,7 @@ Credits for Ejectulate
Ejectulate has approximate, but no literal, code from Kevin Wojniak's Semulov (New-BSD license, but no actual code used). Big thanks for when to use Disk Arbitration and when to use FileManager to eject volumes.
http://code.google.com/p/semulov/
-Ejectulate uses an expanded CollectionUtils, original from MYUtilities by Jens Alfke. License unknown.
-https://bitbucket.org/snej/myutilities/
-
ImageAndTextCell comes from the Apple sample code project called DragNDropOutlineView.
-NSObject+BlockObservation.h is by Andy Matuschak.
-andymatuschak.org
-
Rogue Amoeba figured out the media key voodoo.
http://www.rogueamoeba.com/utm/archives/MediaKeys.m
View
62 Ejectulate.xcodeproj/project.pbxproj
@@ -8,9 +8,7 @@
/* Begin PBXBuildFile section */
1CB4C6C512A8642B0074349E /* DiskArbitration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1CB4C6C412A8642B0074349E /* DiskArbitration.framework */; };
- 1CDA338D12A9C54F00412DB4 /* CollectionUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CDA337612A9C54F00412DB4 /* CollectionUtils.m */; };
1CDA338E12A9C54F00412DB4 /* ImageAndTextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CDA337812A9C54F00412DB4 /* ImageAndTextCell.m */; };
- 1CDA338F12A9C54F00412DB4 /* NSObject+BlockObservation.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CDA337A12A9C54F00412DB4 /* NSObject+BlockObservation.m */; };
1CDA339112A9C54F00412DB4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1CDA337D12A9C54F00412DB4 /* InfoPlist.strings */; };
1CDA339212A9C54F00412DB4 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1CDA337F12A9C54F00412DB4 /* MainWindow.xib */; };
1CDA339312A9C54F00412DB4 /* EJAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CDA338312A9C54F00412DB4 /* EJAppDelegate.m */; };
@@ -22,19 +20,20 @@
1CE00D3512A9E6F10086846F /* NWLoginItems.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CE00D3412A9E6F10086846F /* NWLoginItems.m */; };
1CE00E0412AA19350086846F /* Ejectulate.icns in Resources */ = {isa = PBXBuildFile; fileRef = 1CE00E0312AA19350086846F /* Ejectulate.icns */; };
1CE00F6212AB027D0086846F /* EJEjectKeyWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CE00F6112AB027D0086846F /* EJEjectKeyWatcher.m */; };
+ 1CE45898130754580033D779 /* NSArray+NWHandy.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CE45889130754580033D779 /* NSArray+NWHandy.m */; };
+ 1CE45899130754580033D779 /* NSDictionary+NWHandy.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CE4588B130754580033D779 /* NSDictionary+NWHandy.m */; };
+ 1CE4589A130754580033D779 /* NSIndexPath+NWHandy.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CE4588D130754580033D779 /* NSIndexPath+NWHandy.m */; };
+ 1CE4589B130754580033D779 /* NSObject+NWBlockObservation.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CE4588F130754580033D779 /* NSObject+NWBlockObservation.m */; };
+ 1CE4589C130754580033D779 /* NWBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CE45893130754580033D779 /* NWBox.m */; };
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
1CB4C6C412A8642B0074349E /* DiskArbitration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiskArbitration.framework; path = System/Library/Frameworks/DiskArbitration.framework; sourceTree = SDKROOT; };
- 1CDA337512A9C54F00412DB4 /* CollectionUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollectionUtils.h; sourceTree = "<group>"; };
- 1CDA337612A9C54F00412DB4 /* CollectionUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CollectionUtils.m; sourceTree = "<group>"; };
1CDA337712A9C54F00412DB4 /* ImageAndTextCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageAndTextCell.h; sourceTree = "<group>"; };
1CDA337812A9C54F00412DB4 /* ImageAndTextCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImageAndTextCell.m; sourceTree = "<group>"; };
- 1CDA337912A9C54F00412DB4 /* NSObject+BlockObservation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+BlockObservation.h"; sourceTree = "<group>"; };
- 1CDA337A12A9C54F00412DB4 /* NSObject+BlockObservation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+BlockObservation.m"; sourceTree = "<group>"; };
1CDA337C12A9C54F00412DB4 /* Ejectulate-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Ejectulate-Info.plist"; sourceTree = "<group>"; };
1CDA337E12A9C54F00412DB4 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
1CDA337F12A9C54F00412DB4 /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = "<group>"; };
@@ -55,6 +54,22 @@
1CE00E0312AA19350086846F /* Ejectulate.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Ejectulate.icns; sourceTree = "<group>"; };
1CE00F6012AB027D0086846F /* EJEjectKeyWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EJEjectKeyWatcher.h; sourceTree = "<group>"; };
1CE00F6112AB027D0086846F /* EJEjectKeyWatcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EJEjectKeyWatcher.m; sourceTree = "<group>"; };
+ 1CE45888130754580033D779 /* NSArray+NWHandy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+NWHandy.h"; sourceTree = "<group>"; };
+ 1CE45889130754580033D779 /* NSArray+NWHandy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+NWHandy.m"; sourceTree = "<group>"; };
+ 1CE4588A130754580033D779 /* NSDictionary+NWHandy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+NWHandy.h"; sourceTree = "<group>"; };
+ 1CE4588B130754580033D779 /* NSDictionary+NWHandy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+NWHandy.m"; sourceTree = "<group>"; };
+ 1CE4588C130754580033D779 /* NSIndexPath+NWHandy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSIndexPath+NWHandy.h"; sourceTree = "<group>"; };
+ 1CE4588D130754580033D779 /* NSIndexPath+NWHandy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSIndexPath+NWHandy.m"; sourceTree = "<group>"; };
+ 1CE4588E130754580033D779 /* NSObject+NWBlockObservation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+NWBlockObservation.h"; sourceTree = "<group>"; };
+ 1CE4588F130754580033D779 /* NSObject+NWBlockObservation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+NWBlockObservation.m"; sourceTree = "<group>"; };
+ 1CE45890130754580033D779 /* NSSet+NWHandy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSSet+NWHandy.h"; sourceTree = "<group>"; };
+ 1CE45891130754580033D779 /* NSSortDescriptor+NWHandy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSSortDescriptor+NWHandy.h"; sourceTree = "<group>"; };
+ 1CE45892130754580033D779 /* NWBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NWBox.h; sourceTree = "<group>"; };
+ 1CE45893130754580033D779 /* NWBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NWBox.m; sourceTree = "<group>"; };
+ 1CE45894130754580033D779 /* NWCollections.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NWCollections.h; sourceTree = "<group>"; };
+ 1CE45895130754580033D779 /* NWHandy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NWHandy.h; sourceTree = "<group>"; };
+ 1CE45896130754580033D779 /* NWLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NWLog.h; sourceTree = "<group>"; };
+ 1CE45897130754580033D779 /* NWPrinting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NWPrinting.h; sourceTree = "<group>"; };
29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
8D1107320486CEB800E47090 /* Ejectulate.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Ejectulate.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -103,12 +118,9 @@
1CDA337412A9C54F00412DB4 /* lib */ = {
isa = PBXGroup;
children = (
- 1CDA337512A9C54F00412DB4 /* CollectionUtils.h */,
- 1CDA337612A9C54F00412DB4 /* CollectionUtils.m */,
1CDA337712A9C54F00412DB4 /* ImageAndTextCell.h */,
1CDA337812A9C54F00412DB4 /* ImageAndTextCell.m */,
- 1CDA337912A9C54F00412DB4 /* NSObject+BlockObservation.h */,
- 1CDA337A12A9C54F00412DB4 /* NSObject+BlockObservation.m */,
+ 1CE45887130754580033D779 /* NWHandy */,
1CE00D3312A9E6F10086846F /* NWLoginItems.h */,
1CE00D3412A9E6F10086846F /* NWLoginItems.m */,
);
@@ -147,6 +159,29 @@
path = src;
sourceTree = "<group>";
};
+ 1CE45887130754580033D779 /* NWHandy */ = {
+ isa = PBXGroup;
+ children = (
+ 1CE45888130754580033D779 /* NSArray+NWHandy.h */,
+ 1CE45889130754580033D779 /* NSArray+NWHandy.m */,
+ 1CE4588A130754580033D779 /* NSDictionary+NWHandy.h */,
+ 1CE4588B130754580033D779 /* NSDictionary+NWHandy.m */,
+ 1CE4588C130754580033D779 /* NSIndexPath+NWHandy.h */,
+ 1CE4588D130754580033D779 /* NSIndexPath+NWHandy.m */,
+ 1CE4588E130754580033D779 /* NSObject+NWBlockObservation.h */,
+ 1CE4588F130754580033D779 /* NSObject+NWBlockObservation.m */,
+ 1CE45890130754580033D779 /* NSSet+NWHandy.h */,
+ 1CE45891130754580033D779 /* NSSortDescriptor+NWHandy.h */,
+ 1CE45892130754580033D779 /* NWBox.h */,
+ 1CE45893130754580033D779 /* NWBox.m */,
+ 1CE45894130754580033D779 /* NWCollections.h */,
+ 1CE45895130754580033D779 /* NWHandy.h */,
+ 1CE45896130754580033D779 /* NWLog.h */,
+ 1CE45897130754580033D779 /* NWPrinting.h */,
+ );
+ path = NWHandy;
+ sourceTree = "<group>";
+ };
29B97314FDCFA39411CA2CEA /* Ejectulate */ = {
isa = PBXGroup;
children = (
@@ -231,9 +266,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 1CDA338D12A9C54F00412DB4 /* CollectionUtils.m in Sources */,
1CDA338E12A9C54F00412DB4 /* ImageAndTextCell.m in Sources */,
- 1CDA338F12A9C54F00412DB4 /* NSObject+BlockObservation.m in Sources */,
1CDA339312A9C54F00412DB4 /* EJAppDelegate.m in Sources */,
1CDA339412A9C54F00412DB4 /* EJWindowController.m in Sources */,
1CDA339512A9C54F00412DB4 /* EJEjectableVolumesWatcher.m in Sources */,
@@ -242,6 +275,11 @@
1CDA339812A9C54F00412DB4 /* main.m in Sources */,
1CE00D3512A9E6F10086846F /* NWLoginItems.m in Sources */,
1CE00F6212AB027D0086846F /* EJEjectKeyWatcher.m in Sources */,
+ 1CE45898130754580033D779 /* NSArray+NWHandy.m in Sources */,
+ 1CE45899130754580033D779 /* NSDictionary+NWHandy.m in Sources */,
+ 1CE4589A130754580033D779 /* NSIndexPath+NWHandy.m in Sources */,
+ 1CE4589B130754580033D779 /* NSObject+NWBlockObservation.m in Sources */,
+ 1CE4589C130754580033D779 /* NWBox.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
152 lib/CollectionUtils.h
@@ -1,152 +0,0 @@
-//
-// CollectionUtils.h
-// MYUtilities
-//
-// Created by Jens Alfke on 1/5/08.
-// Copyright 2008 Jens Alfke. All rights reserved.
-//
-
-#import <Foundation/Foundation.h>
-#define _MYUTILITIES_COLLECTIONUTILS_ 1
-
-// Collection creation conveniences:
-
-#define $array(OBJS...) ({ \
- id objs[]={OBJS}; \
- [NSArray arrayWithObjects:objs count:(sizeof(objs) / sizeof(id))]; \
-})
-
-#define $marray(OBJS...) ({ \
- id objs[]={OBJS}; \
- [NSMutableArray arrayWithObjects:objs count:(sizeof(objs) / sizeof(id))]; \
-})
-
-
-#define $set(OBJS...) ({ \
- id objs[]={OBJS}; \
- [NSSet setWithObjects:objs count:(sizeof(objs) / sizeof(id))]; \
-})
-
-
-#define $dict(PAIRS...) ({ \
- struct _dictpair pairs[]={PAIRS}; \
- _dictof(pairs, (sizeof(pairs ) /sizeof(struct _dictpair)), NO); \
-})
-
-#define $mdict(PAIRS...) ({ \
- struct _dictpair pairs[]={PAIRS}; \
- _dictof(pairs, (sizeof(pairs)/sizeof(struct _dictpair)), YES); \
-})
-
-
-// An array of NSSortDescriptors, one per argument. First character of each
-// argument specifies + (ascending) or - (descending); second-through-end is
-// key.
-// For example, the following two sections are equivalent:
-// $sort(@"-priority", @"+date");
-//
-// [NSArray arrayWithObjects:
-// [[[NSSortDescriptor alloc] initWithKey:@"priority" ascending:NO]
-// autorelease],
-// [[[NSSortDescriptor alloc] initWithKey:@"date" ascending:YES]
-// autorelease],
-// nil];
-#define $sort(DESCRIPTORS...) ({ \
- NSString *descriptors[]={DESCRIPTORS}; \
- _sortof(descriptors, (sizeof(descriptors)/sizeof(NSString *))); \
-})
-
-
-#define $pred(ETC...) [NSPredicate predicateWithFormat:ETC]
-
-
-// Return type is id so you can cast, but the class will be one of
-// NSValue or NSNumber, as appropriate.
-#define $box(VAL) ({ \
- __typeof(VAL) v = (VAL); \
- _box(&v, @encode(__typeof(v))); \
-})
-
-
-// Apply a selector to each array element, returning an array of the results:
-NSArray* $apply(NSArray *src, SEL selector, id defaultValue);
-NSArray* $applyKeyPath(NSArray *src, NSString *keyPath, id defaultValue);
-
-
-// Object conveniences:
-
-// Like -isEqual: but works even if either/both are nil
-BOOL $equal(id obj1, id obj2);
-
-NSString* $string( const char *utf8Str );
-
-#define $sprintf(FORMAT, ARGS...) [NSString stringWithFormat:(FORMAT), ARGS]
-
-#define $cast(CLASSNAME,OBJ) ((CLASSNAME*)(_cast([CLASSNAME class],(OBJ))))
-#define $castNotNil(CLASSNAME,OBJ) ( \
- (CLASSNAME*)(_castNotNil([CLASSNAME class], (OBJ))) \
-)
-#define $castIf(CLASSNAME,OBJ) ( \
- (CLASSNAME*)(_castIf([CLASSNAME class], (OBJ))) \
-)
-#define $castArrayOf(ITEMCLASSNAME,OBJ) \
- _castArrayOf([ITEMCLASSNAME class], (OBJ)))
-
-void setObj(id *var, id value);
-BOOL ifSetObj(id *var, id value);
-void setObjCopy(id *var, id valueToCopy);
-BOOL ifSetObjCopy(id *var, id value);
-
-static inline void setString(NSString **var, NSString *value)
-{
- setObjCopy(var,value);
-}
-
-static inline BOOL ifSetString(NSString **var, NSString *value)
-{
- return ifSetObjCopy(var,value);
-}
-
-BOOL kvSetSet(id owner, NSString *property, NSMutableSet *set, NSSet *newSet);
-BOOL kvAddToSet(id owner, NSString *property, NSMutableSet *set, id objToAdd);
-BOOL kvRemoveFromSet(id owner,
- NSString *property,
- NSMutableSet *set,
- id objToRemove);
-
-
-#define $true ((NSNumber*)kCFBooleanTrue)
-#define $false ((NSNumber*)kCFBooleanFalse)
-
-
-@interface NSArray (CollectionUtils)
-
-// Return the first object in this array, or nil if this array is empty.
-- (id)firstObject;
-
-@end
-
-
-@interface NSMutableArray (CollectionUtils)
-
-// Randomize the order of this array's contents. (Fisher-Yates)
-- (void)shuffle;
-
-// Remove and return the first object in this array, or nil if there are none.
-- (id)popFirstObject;
-
-@end
-
-
-// Internals (don't use directly)
-struct _dictpair { id key; id value; };
-NSDictionary* _dictof(const struct _dictpair* pairs,
- size_t count,
- BOOL mutable);
-NSMutableDictionary* _mdictof(const struct _dictpair*, size_t count);
-NSArray *_sortof(NSString **directionedKeys, size_t count);
-id _box(const void *value, const char *encoding);
-id _cast(Class,id);
-id _castNotNil(Class,id);
-id _castIf(Class,id);
-NSArray* _castArrayOf(Class,NSArray*);
View
322 lib/CollectionUtils.m
@@ -1,322 +0,0 @@
-//
-// CollectionUtils.m
-// MYUtilities
-//
-// Created by Jens Alfke on 1/5/08.
-// Copyright 2008 Jens Alfke. All rights reserved.
-//
-
-#import "CollectionUtils.h"
-
-
-@implementation NSArray (CollectionUtils)
-
-- (id)firstObject
-{
- return (([self count] == 0) ? nil : [self objectAtIndex:0]);
-}
-
-@end
-
-
-@implementation NSMutableArray (CollectionUtils)
-
-- (void)shuffle
-{
- for (NSInteger i = [self count] - 1; i >= 1; i--)
- [self exchangeObjectAtIndex:i withObjectAtIndex:(arc4random() % (i + 1))];
-}
-
-- (id)popFirstObject
-{
- id first = [self firstObject];
- if (first)
- [self removeObjectAtIndex:0];
- return first;
-}
-
-@end
-
-
-NSDictionary* _dictof(const struct _dictpair* pairs,
- size_t count,
- BOOL mutable)
-{
- id objects[count], keys[count];
- size_t n = 0;
- for(size_t i = 0; i < count; i++, pairs++)
- {
- if (!pairs->value)
- continue;
- objects[n] = pairs->value;
- keys[n] = pairs->key;
- n++;
- }
- if (mutable)
- return [NSMutableDictionary dictionaryWithObjects:objects
- forKeys:keys
- count:n];
- else
- return [NSDictionary dictionaryWithObjects:objects forKeys:keys count:n];
-}
-
-NSArray *_sortof(NSString **directionedKeys, size_t count)
-{
- NSMutableArray *descriptors = [NSMutableArray array];
- for (NSInteger i = 0; i < count; i++)
- {
- NSString *key = directionedKeys[i];
- BOOL ascending = ([key characterAtIndex:0] == '+');
- NSSortDescriptor *desc = [[[NSSortDescriptor alloc] initWithKey:
- [key substringFromIndex:1] ascending:ascending] autorelease];
- [descriptors addObject:desc];
- }
- return descriptors;
-}
-
-NSArray* $apply(NSArray *src, SEL selector, id defaultValue)
-{
- NSMutableArray *dst = [NSMutableArray arrayWithCapacity:[src count]];
- for(id obj in src)
- {
- id result = [obj performSelector:selector] ?: defaultValue;
- [dst addObject:result];
- }
- return dst;
-}
-
-NSArray* $applyKeyPath(NSArray *src, NSString *keyPath, id defaultValue)
-{
- NSMutableArray *dst = [NSMutableArray arrayWithCapacity:[src count]];
- for(id obj in src)
- {
- id result = [obj valueForKeyPath:keyPath] ?: defaultValue;
- [dst addObject:result];
- }
- return dst;
-}
-
-
-// Like -isEqual: but works even if either/both are nil
-BOOL $equal(id obj1, id obj2)
-{
- if (obj1)
- return obj2 && [obj1 isEqual:obj2];
- else
- return obj2 == nil;
-}
-
-
-id _box(const void *value, const char *encoding)
-{
- // file:///Developer/Documentation/DocSets/
- // com.apple.ADC_Reference_Library.DeveloperTools.docset/Contents/
- // Resources/Documents/documentation/DeveloperTools/gcc-4.0.1/gcc/
- // Type-encoding.html
- char e = encoding[0];
- if(e == 'r') // ignore 'const' modifier
- e = encoding[1];
- switch (e)
- {
- case 'c': return [NSNumber numberWithChar:*(char*)value];
- case 'C': return [NSNumber numberWithUnsignedChar:*(char*)value];
- case 's': return [NSNumber numberWithShort:*(short*)value];
- case 'S':
- return [NSNumber numberWithUnsignedShort:*(unsigned short*)value];
- case 'i': return [NSNumber numberWithInt:*(int*)value];
- case 'I': return [NSNumber numberWithUnsignedInt:*(unsigned int*)value];
- case 'l': return [NSNumber numberWithLong:*(long*)value];
- case 'L':
- return [NSNumber numberWithUnsignedLong:*(unsigned long*)value];
- case 'q': return [NSNumber numberWithLongLong:*(long long*)value];
- case 'Q': {
- unsigned long long *longlong_value = (unsigned long long*)value;
- return [NSNumber numberWithUnsignedLongLong:*longlong_value];
- }
- case 'f': return [NSNumber numberWithFloat:*(float*)value];
- case 'd': return [NSNumber numberWithDouble:*(double*)value];
- case '*': return [NSString stringWithUTF8String:*(char**)value];
- case '@': return *(id*)value;
- default: return [NSValue value:value withObjCType:encoding];
- }
-}
-
-
-id _cast(Class requiredClass, id object)
-{
- if(object && ![object isKindOfClass:requiredClass])
- [NSException raise:NSInvalidArgumentException
- format:@"%@ required, but got %@ %p",
- requiredClass, [object class], object];
- return object;
-}
-
-id _castNotNil(Class requiredClass, id object)
-{
- if(![object isKindOfClass:requiredClass])
- [NSException raise:NSInvalidArgumentException
- format:@"%@ required, but got %@ %p",
- requiredClass, [object class], object];
- return object;
-}
-
-id _castIf(Class requiredClass, id object)
-{
- if(object && ![object isKindOfClass:requiredClass])
- object = nil;
- return object;
-}
-
-NSArray* _castArrayOf(Class itemClass, NSArray *a)
-{
- id item;
- for (item in $cast(NSArray,a))
- _cast(itemClass,item);
- return a;
-}
-
-
-void setObj(id *var, id value)
-{
- if(value == *var)
- return;
- [*var release];
- *var = [value retain];
-}
-
-BOOL ifSetObj(id *var, id value)
-{
- if(value != *var && ![value isEqual:*var])
- {
- [*var release];
- *var = [value retain];
- return YES;
- }
- else
- {
- return NO;
- }
-}
-
-void setObjCopy(id *var, id valueToCopy)
-{
- if(valueToCopy == *var)
- return;
- [*var release];
- *var = [valueToCopy copy];
-}
-
-BOOL ifSetObjCopy(id *var, id value)
-{
- if(value != *var && ![value isEqual:*var])
- {
- [*var release];
- *var = [value copy];
- return YES;
- }
- else
- {
- return NO;
- }
-}
-
-
-NSString* $string(const char *utf8Str)
-{
- if(utf8Str)
- return [NSString stringWithCString:utf8Str encoding:NSUTF8StringEncoding];
- else
- return nil;
-}
-
-
-BOOL kvSetSet(id owner, NSString *property, NSMutableSet *set, NSSet *newSet)
-{
- if (!newSet)
- newSet = [NSSet set];
- if (![set isEqualToSet:newSet])
- {
- [owner willChangeValueForKey:property
- withSetMutation:NSKeyValueSetSetMutation
- usingObjects:newSet];
- [set setSet: newSet];
- [owner didChangeValueForKey:property
- withSetMutation:NSKeyValueSetSetMutation
- usingObjects:newSet];
- return YES;
- }
- else
- {
- return NO;
- }
-}
-
-
-BOOL kvAddToSet(id owner, NSString *property, NSMutableSet *set, id objToAdd)
-{
- if (![set containsObject:objToAdd])
- {
- NSSet *changedObjects = [[NSSet alloc] initWithObjects:&objToAdd count:1];
- [owner willChangeValueForKey:property
- withSetMutation:NSKeyValueUnionSetMutation
- usingObjects:changedObjects];
- [set addObject:objToAdd];
- [owner didChangeValueForKey:property
- withSetMutation:NSKeyValueUnionSetMutation
- usingObjects:changedObjects];
- [changedObjects release];
- return YES;
- }
- else
- {
- return NO;
- }
-}
-
-
-BOOL kvRemoveFromSet(id owner,
- NSString *property,
- NSMutableSet *set,
- id objToRemove)
-{
- if ([set containsObject:objToRemove])
- {
- NSSet *changed = [[NSSet alloc] initWithObjects:&objToRemove count:1];
- [owner willChangeValueForKey: property
- withSetMutation: NSKeyValueMinusSetMutation
- usingObjects: changed];
- [set removeObject: objToRemove];
- [owner didChangeValueForKey: property
- withSetMutation: NSKeyValueMinusSetMutation
- usingObjects: changed];
- [changed release];
- return YES;
- }
- else
- {
- return NO;
- }
-}
-
-
-/*
- Copyright (c) 2008, Jens Alfke <jens@mooseyard.com>. All rights reserved.
-
- Redistribution and use in source and binary forms, with or without modification, are permitted
- provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- and the following disclaimer in the documentation and/or other materials provided with the
- distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
- BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
View
46 lib/NSObject+BlockObservation.h
@@ -1,46 +0,0 @@
-//
-// NSObject+BlockObservation.h
-// Version 1.0
-//
-// Andy Matuschak
-// andy@andymatuschak.org
-// Public domain because I love you. Let me know how you use it.
-//
-// NTW 2009-Oct-21: Added selectors with an options argument.
-// NTW 2009-Oct-30: Transplanted new observation key from MYUtilities's
-// KVUtils.
-
-#import <Cocoa/Cocoa.h>
-
-typedef NSString AMBlockToken;
-
-typedef void (^AMBlockTask)(id obj, NSDictionary *change);
-
-// Or MYKeyValueObservingOptionOnce with your observation options to cause the
-// observer to remove itself upon the first change notification.
-// Idea and line of code from MYUtilities.
-enum {
- MYKeyValueObservingOptionOnce = 1<<31
-};
-
-@interface NSObject (AMBlockObservation)
-
-- (AMBlockToken*)addObserverForKeyPath:(NSString*)keyPath
- task:(AMBlockTask)task;
-
-- (AMBlockToken*)addObserverForKeyPath:(NSString*)keyPath
- options:(NSKeyValueObservingOptions)options
- task:(AMBlockTask)task;
-
-- (AMBlockToken*)addObserverForKeyPath:(NSString*)keyPath
- onQueue:(NSOperationQueue*)queue
- task:(AMBlockTask)task;
-
-- (AMBlockToken*)addObserverForKeyPath:(NSString*)keyPath
- options:(NSKeyValueObservingOptions)options
- onQueue:(NSOperationQueue*)queue
- task:(AMBlockTask)task;
-
-- (void)removeObserverWithBlockToken:(AMBlockToken *)token;
-
-@end
View
155 lib/NSObject+BlockObservation.m
@@ -1,155 +0,0 @@
-//
-// NSObject+BlockObservation.h
-// Version 1.0
-//
-// Andy Matuschak
-// andy@andymatuschak.org
-// Public domain because I love you. Let me know how you use it.
-//
-
-#import "NSObject+BlockObservation.h"
-#import <dispatch/dispatch.h>
-#import <objc/runtime.h>
-
-@interface AMObserverTrampoline : NSObject
-{
- __weak id observee;
- NSString *keyPath;
- AMBlockTask task;
- NSOperationQueue *queue;
- NSKeyValueObservingOptions options;
-}
-
-- (AMObserverTrampoline*)initObservingObject:(id)obj
- keyPath:(NSString*)newKeyPath
- options:(NSKeyValueObservingOptions)newOptions
- onQueue:(NSOperationQueue*)newQueue
- task:(AMBlockTask)newTask;
-
-- (void)cancelObservation;
-
-@end
-
-
-@implementation AMObserverTrampoline
-
-static NSString *AMObserverTrampolineContext = @"AMObserverTrampolineContext";
-
-- (AMObserverTrampoline*)initObservingObject:(id)obj
- keyPath:(NSString*)newKeyPath
- options:(NSKeyValueObservingOptions)newOptions
- onQueue:(NSOperationQueue*)newQueue
- task:(AMBlockTask)newTask
-{
- self = [super init];
- if (self != nil)
- {
- task = [newTask copy];
- keyPath = [newKeyPath copy];
- queue = [newQueue retain];
- observee = obj;
- options = newOptions;
-
- // Clear out our customized options before passing them on.
- // From MYUtilities.
- newOptions &= ~MYKeyValueObservingOptionOnce;
-
- [observee addObserver:self
- forKeyPath:keyPath
- options:newOptions
- context:AMObserverTrampolineContext];
- }
- return self;
-}
-
-- (void)observeValueForKeyPath:(NSString*)aKeyPath
- ofObject:(id)object
- change:(NSDictionary*)change
- context:(void*)context
-{
- if (context != AMObserverTrampolineContext)
- {
- [super observeValueForKeyPath:aKeyPath ofObject:object change:change context:context];
- return;
- }
-
- // Not sure if we really need this on the next run loop iteration. Seemed right.
- if (options & MYKeyValueObservingOptionOnce)
- [self performSelector:@selector(cancelObservation) withObject:nil afterDelay:0.0];
-
- if (queue)
- [queue addOperationWithBlock:^{ task(object, change); }];
- else
- task(object, change);
-}
-
-- (void)cancelObservation
-{
- [observee removeObserver:self forKeyPath:keyPath];
-}
-
-- (void)dealloc
-{
- [self cancelObservation];
- [task release];
- [keyPath release];
- [queue release];
- [super dealloc];
-}
-
-@end
-
-
-static NSString *AMObserverMapKey = @"org.andymatuschak.observerMap";
-
-
-@implementation NSObject (AMBlockObservation)
-
-- (AMBlockToken *)addObserverForKeyPath:(NSString *)keyPath task:(AMBlockTask)task
-{
- return [self addObserverForKeyPath:keyPath options:0 onQueue:nil task:task];
-}
-
-- (AMBlockToken*)addObserverForKeyPath:(NSString*)keyPath
- options:(NSKeyValueObservingOptions)options
- task:(AMBlockTask)task
-{
- return [self addObserverForKeyPath:keyPath options:options onQueue:nil task:task];
-}
-
-- (AMBlockToken*)addObserverForKeyPath:(NSString*)keyPath
- onQueue:(NSOperationQueue*)queue
- task:(AMBlockTask)task
-{
- return [self addObserverForKeyPath:keyPath options:0 onQueue:queue task:task];
-}
-
-- (AMBlockToken*)addObserverForKeyPath:(NSString*)keyPath
- options:(NSKeyValueObservingOptions)options
- onQueue:(NSOperationQueue*)queue
- task:(AMBlockTask)task
-{
- AMBlockToken *token = [[NSProcessInfo processInfo] globallyUniqueString];
- dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- if (!objc_getAssociatedObject(self, AMObserverMapKey))
- objc_setAssociatedObject(self, AMObserverMapKey, [NSMutableDictionary dictionary], OBJC_ASSOCIATION_RETAIN);
- AMObserverTrampoline *trampoline = [[[AMObserverTrampoline alloc] initObservingObject:self keyPath:keyPath options:options onQueue:queue task:task] autorelease];
- [objc_getAssociatedObject(self, AMObserverMapKey) setObject:trampoline forKey:token];
- });
- return token;
-}
-
-- (void)removeObserverWithBlockToken:(AMBlockToken *)token
-{
- NSMutableDictionary *observationDictionary = objc_getAssociatedObject(self, AMObserverMapKey);
- AMObserverTrampoline *trampoline = [observationDictionary objectForKey:token];
- if (!trampoline)
- {
- NSLog(@"Tried to remove non-existent observer on %@ for token %@", self, token);
- return;
- }
- [trampoline cancelObservation];
- [observationDictionary removeObjectForKey:token];
-}
-
-@end
View
28 lib/NWHandy/NSArray+NWHandy.h
@@ -0,0 +1,28 @@
+//
+// NSArray+NWHandy.h
+// NWHandy
+//
+// Created by Nolan Waite on 10-12-12.
+// Copyright 2010 Nolan Waite. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+#define nw_array(OBJECTS...) ({\
+ id _objects_[] = {OBJECTS}; \
+ [NSArray arrayWithObjects:_objects_ count:sizeof(_objects_) / sizeof(id)]; \
+})
+
+#define nw_marray(OBJECTS...) ({\
+ id _objects_[] = {OBJECTS}; \
+ [NSMutableArray arrayWithObjects:_objects_ \
+ count:sizeof(_objects_) / sizeof(id)]; \
+})
+
+
+@interface NSArray (NWHandy)
+
+- (id)nw_firstObject;
+
+@end
View
19 lib/NWHandy/NSArray+NWHandy.m
@@ -0,0 +1,19 @@
+//
+// NSArray+NWHandy.m
+// NWHandy
+//
+// Created by Nolan Waite on 10-12-12.
+// Copyright 2010 Nolan Waite. All rights reserved.
+//
+
+#import "NSArray+NWHandy.h"
+
+
+@implementation NSArray (NWHandy)
+
+- (id)nw_firstObject
+{
+ return ([self count] > 0 ? [self objectAtIndex:0] : nil);
+}
+
+@end
View
30 lib/NWHandy/NSDictionary+NWHandy.h
@@ -0,0 +1,30 @@
+//
+// NSDictionary+NWHandy.h
+// NWHandy
+//
+// Created by Nolan Waite on 10-12-12.
+// Copyright 2010 Nolan Waite. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+#define nw_dict(OBJECTS...) ({ \
+ id _objects_[] = {OBJECTS}; \
+ [NSDictionary nw_dictionaryWithKeysAndObjects:_objects_ \
+ count:(sizeof(_objects_) / sizeof(id))]; \
+})
+
+#define nw_mdict(OBJECTS...) ({ \
+ id _objects_[] = {OBJECTS}; \
+ [NSMutableDictionary nw_dictionaryWithKeysAndObjects:_objects_ \
+ count:(sizeof(_objects_) / sizeof(id))]; \
+})
+
+
+@interface NSDictionary (NWHandy)
+
++ (id)nw_dictionaryWithKeysAndObjects:(id*)keysAndObjects
+ count:(NSUInteger)count;
+
+@end
View
29 lib/NWHandy/NSDictionary+NWHandy.m
@@ -0,0 +1,29 @@
+//
+// NSDictionary+NWHandy.m
+// NWHandy
+//
+// Created by Nolan Waite on 10-12-12.
+// Copyright 2010 Nolan Waite. All rights reserved.
+//
+
+#import "NSDictionary+NWHandy.h"
+
+
+@implementation NSDictionary (NWHandy)
+
++ (id)nw_dictionaryWithKeysAndObjects:(id*)keysAndObjects
+ count:(NSUInteger)count
+{
+ NSAssert((count % 2 == 0), @"unmatched keys and values");
+
+ NSMutableArray *keys = [NSMutableArray array];
+ NSMutableArray *objects = [NSMutableArray array];
+ for (NSUInteger i = 0; i < count; i += 2)
+ {
+ [keys addObject:keysAndObjects[i]];
+ [objects addObject:keysAndObjects[i + 1]];
+ }
+ return [self dictionaryWithObjects:objects forKeys:keys];
+}
+
+@end
View
16 lib/NWHandy/NSIndexPath+NWHandy.h
@@ -0,0 +1,16 @@
+//
+// NSIndexPath+NWHandy.h
+// NWHandy
+//
+// Created by Nolan Waite on 11-02-10.
+// Copyright 2011 Nolan Waite. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+@interface NSIndexPath (NWHandy)
+
+- (NSUInteger)nw_lastIndex;
+
+@end
View
22 lib/NWHandy/NSIndexPath+NWHandy.m
@@ -0,0 +1,22 @@
+//
+// NSIndexPath+NWHandy.m
+// NWHandy
+//
+// Created by Nolan Waite on 11-02-10.
+// Copyright 2011 Nolan Waite. All rights reserved.
+//
+
+#import "NSIndexPath+NWHandy.h"
+
+
+@implementation NSIndexPath (NWHandy)
+
+- (NSUInteger)nw_lastIndex
+{
+ if ([self length] == 0)
+ return NSNotFound;
+ else
+ return [self indexAtPosition:([self length] - 1)];
+}
+
+@end
View
43 lib/NWHandy/NSObject+NWBlockObservation.h
@@ -0,0 +1,43 @@
+//
+// NSObject+NWBlockObservation.h
+// NWHandy
+//
+// Created by Nolan Waite on 10-12-12.
+// Copyright 2010 Nolan Waite. All rights reserved.
+//
+// Original by Andy Matuschak who is awesome.
+// andy@andymatuschak.org
+// https://gist.github.com/153676
+//
+
+#import <Foundation/Foundation.h>
+
+
+#if NS_BLOCKS_AVAILABLE && defined(MAC_OS_X_VERSION_10_6)
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+
+typedef NSString NWBlockToken;
+
+typedef void (^NWBlockTask)(id obj, NSDictionary *change);
+
+
+@interface NSObject (NWBlockObservation)
+
+- (NWBlockToken*)nw_addObserverForKeyPath:(NSString*)keyPath
+ task:(NWBlockTask)task;
+
+- (NWBlockToken*)nw_addObserverForKeyPath:(NSString*)keyPath
+ options:(NSKeyValueObservingOptions)options
+ task:(NWBlockTask)task;
+
+- (NWBlockToken*)nw_addObserverForKeyPath:(NSString*)keyPath
+ options:(NSKeyValueObservingOptions)options
+ onQueue:(NSOperationQueue*)queue
+ task:(NWBlockTask)task;
+
+- (void)nw_removeObserverWithBlockToken:(NWBlockToken *)token;
+
+@end
+
+#endif
+#endif
View
190 lib/NWHandy/NSObject+NWBlockObservation.m
@@ -0,0 +1,190 @@
+//
+// NSObject+NWBlockObservation.m
+// NWHandy
+//
+// Created by Nolan Waite on 10-12-12.
+// Copyright 2010 Nolan Waite. All rights reserved.
+//
+// Original by Andy Matuschak who is awesome.
+// andy@andymatuschak.org
+//
+
+#import "NSObject+NWBlockObservation.h"
+
+
+#if NS_BLOCKS_AVAILABLE && defined(MAC_OS_X_VERSION_10_6)
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+
+#import <dispatch/dispatch.h>
+#import <objc/runtime.h>
+
+
+@interface NWObserverTrampoline : NSObject
+{
+ __weak id observee;
+ NSString *keyPath;
+ NWBlockTask task;
+ NSOperationQueue *queue;
+ dispatch_once_t cancellationPredicate;
+}
+
+- (id)initObservingObject:(id)object
+ keyPath:(NSString*)keyPath
+ options:(NSKeyValueObservingOptions)options
+ onQueue:(NSOperationQueue*)queue
+ task:(NWBlockTask)task;
+
+- (void)cancelObservation;
+
+@end
+
+
+@implementation NWObserverTrampoline
+
+static NSString *NWObserverTrampolineContext = @"NWObserverTrampolineContext";
+
+- (id)initObservingObject:(id)object
+ keyPath:(NSString*)aKeyPath
+ options:(NSKeyValueObservingOptions)options
+ onQueue:(NSOperationQueue*)aQueue
+ task:(NWBlockTask)aTask
+{
+ if ((self = [super init]))
+ {
+ observee = object;
+ keyPath = [aKeyPath copy];
+ task = [aTask copy];
+ queue = [aQueue retain];
+ cancellationPredicate = 0;
+ [observee addObserver:self
+ forKeyPath:keyPath
+ options:options
+ context:NWObserverTrampolineContext];
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ [self cancelObservation];
+ [keyPath release], keyPath = nil;
+ [task release], task = nil;
+ [queue release], queue = nil;
+ [super dealloc];
+}
+
+- (void)observeValueForKeyPath:(NSString*)aKeyPath
+ ofObject:(id)object
+ change:(NSDictionary*)change
+ context:(void*)context
+{
+ if (context == NWObserverTrampolineContext)
+ {
+ if (queue)
+ [queue addOperationWithBlock:^{ task(object, change); }];
+ else
+ task(object, change);
+ }
+}
+
+- (void)cancelObservation
+{
+ dispatch_once(&cancellationPredicate, ^{
+ [observee removeObserver:self forKeyPath:keyPath];
+ observee = nil;
+ });
+}
+
+@end
+
+
+static NSString *NWObserverMapKey = @"ca.nolanw.NWHandy.observerMap";
+static dispatch_queue_t NWObserverMutationQueue = NULL;
+
+static dispatch_queue_t NWObserverMutationQueueCreatingIfNecessary()
+{
+ static dispatch_once_t queueCreationPredicate = 0;
+ dispatch_once(&queueCreationPredicate, ^{
+ const char *label = "ca.nolanw.NWHandy.observationMutationQueue";
+ NWObserverMutationQueue = dispatch_queue_create(label, 0);
+ });
+ return NWObserverMutationQueue;
+}
+
+
+@implementation NSObject (NWBlockObservation)
+
+- (NWBlockToken*)nw_addObserverForKeyPath:(NSString*)keyPath
+ task:(NWBlockTask)task
+{
+ return [self nw_addObserverForKeyPath:keyPath
+ options:0
+ onQueue:nil
+ task:task];
+}
+
+- (NWBlockToken*)nw_addObserverForKeyPath:(NSString*)keyPath
+ options:(NSKeyValueObservingOptions)options
+ task:(NWBlockTask)task
+{
+ return [self nw_addObserverForKeyPath:keyPath
+ options:options
+ onQueue:nil
+ task:task];
+}
+
+- (NWBlockToken*)nw_addObserverForKeyPath:(NSString*)keyPath
+ options:(NSKeyValueObservingOptions)options
+ onQueue:(NSOperationQueue*)queue
+ task:(NWBlockTask)task
+{
+ NWBlockToken *token = [[NSProcessInfo processInfo] globallyUniqueString];
+ dispatch_sync(NWObserverMutationQueueCreatingIfNecessary(), ^{
+ NSMutableDictionary *dict = objc_getAssociatedObject(self,
+ NWObserverMapKey);
+ if (!dict)
+ {
+ dict = [[NSMutableDictionary alloc] init];
+ objc_setAssociatedObject(self, NWObserverMapKey, dict,
+ OBJC_ASSOCIATION_RETAIN);
+ [dict release];
+ }
+ NWObserverTrampoline *trampoline;
+ trampoline = [[NWObserverTrampoline alloc] initObservingObject:self
+ keyPath:keyPath
+ options:options
+ onQueue:queue
+ task:task];
+ [dict setObject:trampoline forKey:token];
+ [trampoline release];
+ });
+ return token;
+}
+
+- (void)nw_removeObserverWithBlockToken:(NWBlockToken *)token;
+{
+ dispatch_sync(NWObserverMutationQueueCreatingIfNecessary(), ^{
+ NSMutableDictionary *dict = objc_getAssociatedObject(self,
+ NWObserverMapKey);
+ NWObserverTrampoline *trampoline = [dict objectForKey:token];
+ if (!trampoline)
+ {
+ NSLog(@"[NSObject(NWBlockObservation) %@]: Ignoring attempt to remove "
+ "nonexistent observer on %@ for token %@.",
+ NSStringFromSelector(_cmd), self, token);
+ return;
+ }
+ [trampoline cancelObservation];
+ [dict removeObjectForKey:token];
+ if ([dict count] == 0)
+ {
+ objc_setAssociatedObject(self, NWObserverMapKey, nil,
+ OBJC_ASSOCIATION_RETAIN);
+ }
+ });
+}
+
+@end
+
+#endif
+#endif
View
21 lib/NWHandy/NSSet+NWHandy.h
@@ -0,0 +1,21 @@
+//
+// NSSet+NWHandy.h
+// NWHandy
+//
+// Created by Nolan Waite on 10-12-28.
+// Copyright 2010 Nolan Waite. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+#define nw_set(OBJECTS...) ({ \
+ id _objects_[] = {OBJECTS}; \
+ [NSSet setWithObjects:_objects_ count:(sizeof(_objects_) / sizeof(id))]; \
+})
+
+#define nw_mset(OBJECTS...) ({ \
+ id _objects_[] = {OBJECTS}; \
+ [NSMutableSet setWithObjects:_objects_ \
+ count:(sizeof(_objects_) / sizeof(id))]; \
+})
View
14 lib/NWHandy/NSSortDescriptor+NWHandy.h
@@ -0,0 +1,14 @@
+//
+// NSSortDescriptor+NWHandy.h
+// NWHandy
+//
+// Created by Nolan Waite on 11-02-09.
+// Copyright 2011 Nolan Waite. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#define nw_sort(KEY) \
+ [[[NSSortDescriptor alloc] initWithKey:[KEY substringFromIndex:1] \
+ ascending:([[KEY substringToIndex:1] \
+ isEqual:@"+"])] autorelease]
View
17 lib/NWHandy/NWBox.h
@@ -0,0 +1,17 @@
+//
+// NWBox.h
+// NWHandy
+//
+// Created by Nolan Waite on 10-12-27.
+// Copyright 2010 Nolan Waite. All rights reserved.
+//
+
+// Box VALUE into an NSNumber or NSString if possible, or an NSValue otherwise.
+#define nw_box(VALUE) ({ \
+ __typeof(VALUE) v = (VALUE); \
+ _nw_box(&v, @encode(__typeof(v))); \
+})
+
+// Does the actual work of boxing the value. You'll want to use the above
+// macro, not this function.
+id _nw_box(const void *value, const char *encoding);
View
41 lib/NWHandy/NWBox.m
@@ -0,0 +1,41 @@
+//
+// NWBox.m
+// NWHandy
+//
+// Created by Nolan Waite on 10-12-27.
+// Copyright 2010 Nolan Waite. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "NWBox.h"
+
+
+id _nw_box(const void *value, const char *encoding)
+{
+ char e = encoding[0];
+ if (e == 'r')
+ e = encoding[1]; // Ignore const
+ switch (e)
+ {
+ case 'c': return [NSNumber numberWithChar:*(char *)value];
+ case 'C': return [NSNumber numberWithUnsignedChar:*(char *)value];
+ case 's': return [NSNumber numberWithShort:*(short *)value];
+ case 'S': {
+ unsigned short *us_value = (unsigned short *)value;
+ return [NSNumber numberWithUnsignedShort:*us_value];
+ }
+ case 'i': return [NSNumber numberWithInt:*(int *)value];
+ case 'I': return [NSNumber numberWithUnsignedInt:*(unsigned int *)value];
+ case 'l': return [NSNumber numberWithLong:*(long *)value];
+ case 'L': return [NSNumber numberWithUnsignedLong:*(unsigned long *)value];
+ case 'q': return [NSNumber numberWithLongLong:*(long long *)value];
+ case 'Q': {
+ unsigned long long *ull_value = (unsigned long long *)value;
+ return [NSNumber numberWithUnsignedLongLong:*ull_value];
+ }
+ case 'f': return [NSNumber numberWithFloat:*(float *)value];
+ case 'd': return [NSNumber numberWithDouble:*(double *)value];
+ case '*': return [NSString stringWithUTF8String:*(char **)value];
+ default: return [NSValue value:value withObjCType:encoding];
+ }
+}
View
24 lib/NWHandy/NWCollections.h
@@ -0,0 +1,24 @@
+//
+// NWCollections.h
+// NWHandy
+//
+// Created by Nolan Waite on 10-12-31.
+// Copyright 2010 Nolan Waite. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+// Generic empty function. Works for anything with a length or count method.
+// Returns YES if collection is empty, NO otherwise.
+static inline BOOL nw_isempty(id collection)
+{
+ if (collection == nil)
+ return YES;
+ else if ([collection respondsToSelector:@selector(length)])
+ return ([collection length] == 0);
+ else if ([collection respondsToSelector:@selector(count)])
+ return ([collection count] == 0);
+ else
+ return NO;
+}
View
19 lib/NWHandy/NWHandy.h
@@ -0,0 +1,19 @@
+/*
+ * NWHandy.h
+ * NWHandy
+ *
+ * Created by Nolan Waite on 10-12-12.
+ * Copyright 2010 Nolan Waite. All rights reserved.
+ *
+ */
+
+#import "NSArray+NWHandy.h"
+#import "NSDictionary+NWHandy.h"
+#import "NSIndexPath+NWHandy.h"
+#import "NSObject+NWBlockObservation.h"
+#import "NSSet+NWHandy.h"
+#import "NSSortDescriptor+NWHandy.h"
+#import "NWBox.h"
+#import "NWCollections.h"
+#import "NWLog.h"
+#import "NWPrinting.h"
View
17 lib/NWHandy/NWLog.h
@@ -0,0 +1,17 @@
+/*
+ * NWLog.h
+ * NWHandy
+ *
+ * Created by Nolan Waite on 10-12-31.
+ * Copyright 2010 Nolan Waite. All rights reserved.
+ *
+ */
+
+#ifdef NDEBUG
+#define NWLog(...)
+#else
+#define NWLog(s, ...) NSLog(@"%s:%d [%@ %@] %@", __FILE__, __LINE__, \
+ NSStringFromClass([self class]), NSStringFromSelector(_cmd), \
+ [NSString stringWithFormat:s,##__VA_ARGS__] \
+)
+#endif
View
55 lib/NWHandy/NWPrinting.h
@@ -0,0 +1,55 @@
+/*
+ * NWPrinting.h
+ * NWHandy
+ *
+ * Created by Nolan Waite on 10-12-29.
+ * Copyright 2010 Nolan Waite. All rights reserved.
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+// Shorten [NSString stringWithFormat:] up a bit.
+#define nw_nsprintf(...) [NSString stringWithFormat:__VA_ARGS__]
+
+
+// forcetype and stringify macros courtesy Mike Ash.
+// http://mikeash.com/pyblog/friday-qa-2010-12-31-c-macro-tips-and-tricks.html
+
+// Make the compiler treat x as the given type no matter what.
+#define nw_forcetype(x, type) *(type *)(__typeof__(x) []){ x }
+
+// Get the geometry types right for both iOS and OS X.
+#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+#define NW_GEOMETRY_PREFIX(x) CG ## x
+#define NW_GEOMETRY_STRING(x) NSStringFromCG ## x
+#else
+#define NW_GEOMETRY_PREFIX(x) NS ## x
+#define NW_GEOMETRY_STRING(x) NSStringFrom ## x
+#endif
+
+// Turn various structs and data types into strings.
+#define nw_stringify(x) \
+ __builtin_choose_expr( \
+ __builtin_types_compatible_p(__typeof__(x), NW_GEOMETRY_PREFIX(Rect)), \
+ NW_GEOMETRY_STRING(Rect)(nw_forcetype(x, NW_GEOMETRY_PREFIX(Rect))), \
+ \
+ __builtin_choose_expr( \
+ __builtin_types_compatible_p(__typeof__(x), NW_GEOMETRY_PREFIX(Size)), \
+ NW_GEOMETRY_STRING(Size)(nw_forcetype(x, NW_GEOMETRY_PREFIX(Size))), \
+ \
+ __builtin_choose_expr( \
+ __builtin_types_compatible_p(__typeof__(x), NW_GEOMETRY_PREFIX(Point)), \
+ NW_GEOMETRY_STRING(Point)(nw_forcetype(x, NW_GEOMETRY_PREFIX(Point))), \
+ \
+ __builtin_choose_expr( \
+ __builtin_types_compatible_p(__typeof__(x), SEL), \
+ NSStringFromSelector(nw_forcetype(x, SEL)), \
+ \
+ __builtin_choose_expr( \
+ __builtin_types_compatible_p(__typeof__(x), NSRange), \
+ NSStringFromRange(nw_forcetype(x, NSRange)), \
+ \
+ [NSValue valueWithBytes:(__typeof__(x) []){ x } \
+ objCType:@encode(__typeof__(x))] \
+)))))
View
8 src/EJAppDelegate.m
@@ -31,7 +31,7 @@ @implementation EJAppDelegate
+ (void)initialize
{
- [[NSUserDefaults standardUserDefaults] registerDefaults:$dict(
+ [[NSUserDefaults standardUserDefaults] registerDefaults:nw_dict(
@"StartOnLogin", @"NO")];
}
@@ -48,9 +48,9 @@ - (void)applicationDidFinishLaunching:(NSNotification *)note
// Handle the user toggling option to start Ejectulate on login.
NSUserDefaultsController *defaults;
defaults = [NSUserDefaultsController sharedUserDefaultsController];
- [defaults addObserverForKeyPath:@"values.StartsOnLogin"
- options:0
- task:^(id obj, NSDictionary *change)
+ [defaults nw_addObserverForKeyPath:@"values.StartsOnLogin"
+ options:0
+ task:^(id obj, NSDictionary *change)
{
// For some reason the change dictionary refuses to set a useful value
// for new, so here we just get it ourselves.
View
5 src/EJEjectableVolumesWatcher.m
@@ -100,8 +100,7 @@ - (NSMutableArray *)ejectableVolumes
EJVolume *wholeDisk = [EJVolume wholeDiskVolumeWithBSDName:BSDName];
if (!wholeDisk)
{
- NSLog(@"%@ failed creating whole disk for BSDName %@",
- NSStringFromSelector(_cmd), BSDName);
+ NWLog(@"failed creating whole disk for BSDName %@", BSDName);
continue;
}
NSMutableArray *children = [NSMutableArray array];
@@ -137,7 +136,7 @@ - (void)addVolume:(EJVolume *)newVolume
{
NSString *BSDName = sharesWholeDisk.wholeDiskBSDName;
EJVolume *newWhole = [EJVolume wholeDiskVolumeWithBSDName:BSDName];
- newWhole.children = $marray(sharesWholeDisk, newVolume);
+ newWhole.children = nw_marray(sharesWholeDisk, newVolume);
NSUInteger index = [kvoVolumes indexOfObject:sharesWholeDisk];
[kvoVolumes replaceObjectAtIndex:index withObject:newWhole];
}
View
11 src/EJWindowController.m
@@ -9,7 +9,6 @@
#import "EJWindowController.h"
#import "EJEjectableVolumesWatcher.h"
#import "EJOutlineView.h"
-#import "CollectionUtils.h"
#import "ImageAndTextCell.h"
@@ -54,7 +53,7 @@ - (NSInteger)tabViewIndex
+ (NSSet *)keyPathsForValuesAffectingTabViewIndex
{
- return $set(@"volumesWatcher.volumes.@count");
+ return nw_set(@"volumesWatcher.volumes.@count");
}
#if 0
@@ -111,7 +110,7 @@ - (CGFloat)titleBarHeight
- (void)setUpWindow
{
- NSArray *buttons = $array(
+ NSArray *buttons = nw_array(
[self.window standardWindowButton:NSWindowMiniaturizeButton],
[self.window standardWindowButton:NSWindowZoomButton]);
NSView *titleBar = [[buttons lastObject] superview];
@@ -161,9 +160,9 @@ - (void)sizeWindowToFit:(NSUInteger)additional
- (void)windowDidLoad
{
- [self.tree addObserverForKeyPath:@"arrangedObjects"
- options:NSKeyValueObservingOptionInitial
- task:^(id obj, NSDictionary *change)
+ [self.tree nw_addObserverForKeyPath:@"arrangedObjects"
+ options:NSKeyValueObservingOptionInitial
+ task:^(id obj, NSDictionary *change)
{
[self.outline expandItem:nil expandChildren:YES];
[self.window center];
View
3 src/Ejectulate_Prefix.pch
@@ -4,6 +4,5 @@
#ifdef __OBJC__
#import <Cocoa/Cocoa.h>
- #import "CollectionUtils.h"
- #import "NSObject+BlockObservation.h"
+ #import "NWHandy.h"
#endif

0 comments on commit a0b4bad

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