Skip to content

Commit

Permalink
Additional functionality to CbC to support Dragons (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
yarneo committed Dec 15, 2017
1 parent 1fcaf77 commit 67c6d97
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 11 deletions.
10 changes: 10 additions & 0 deletions src/CBCCatalogExample.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@
*/
+ (BOOL)catalogIsPrimaryDemo;

/**
Return a BOOL stating whether this example is presentable and should be part of the catalog app.
*/
+ (BOOL)catalogIsPresentable;

/**
Return a BOOL stating whether this example is in debug mode and should appear as the initial view controller.
*/
+ (BOOL)catalogIsDebug;

@optional

/**
Expand Down
19 changes: 19 additions & 0 deletions src/CBCNodeListViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@
*/
FOUNDATION_EXTERN CBCNode *_Nonnull CBCCreateNavigationTree(void);

/**
Returns the root of a CBCNode tree representing only the presentable catalog navigation hierarchy.
Only classes that implement +catalogIsPresentable with a return value of YES,
and +catalogBreadcrumbs and return at least one breadcrumb will be part of the tree.
*/
FOUNDATION_EXTERN CBCNode *_Nonnull CBCCreatePresentableNavigationTree(void);

/**
A node describes a single navigable page in the Catalog by Convention.
Expand All @@ -67,6 +75,14 @@ FOUNDATION_EXTERN CBCNode *_Nonnull CBCCreateNavigationTree(void);
/** The children of this node. */
@property(nonatomic, strong, nonnull) NSArray<CBCNode *> *children;

/**
The example you wish to debug as the initial view controller.
If there are multiple examples with catalogIsDebug returning YES
the debugLeaf will hold the example that has been iterated on last
in the hierarchy tree.
*/
@property(nonatomic, strong, nullable) CBCNode *debugLeaf;

/** Returns YES if this is an example node. */
- (BOOL)isExample;

Expand All @@ -77,6 +93,9 @@ FOUNDATION_EXTERN CBCNode *_Nonnull CBCCreateNavigationTree(void);
*/
- (BOOL)isPrimaryDemo;

/** Returns YES if this is a presentable example. */
- (BOOL)isPresentable;

/** Returns String representation of exampleViewController class name if it exists */
- (nullable NSString *)exampleViewControllerName;

Expand Down
37 changes: 34 additions & 3 deletions src/CBCNodeListViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ @implementation CBCNode {
NSMutableDictionary *_map;
NSMutableArray *_children;
Class _exampleClass;
BOOL _isPresentable;
}

- (instancetype)initWithTitle:(NSString *)title {
Expand All @@ -33,6 +34,7 @@ - (instancetype)initWithTitle:(NSString *)title {
_title = [title copy];
_map = [NSMutableDictionary dictionary];
_children = [NSMutableArray array];
_isPresentable = NO;
CBCFixViewDebuggingIfNeeded();
}
return self;
Expand All @@ -55,6 +57,10 @@ - (void)setExampleClass:(Class)exampleClass {
_exampleClass = exampleClass;
}

- (void)setIsPresentable:(Class)exampleClass {
_isPresentable = CBCCatalogIsPresentableFromClass(exampleClass);
}

- (void)finalizeNode {
_children = [[_children sortedArrayUsingSelector:@selector(compare:)] mutableCopy];
}
Expand Down Expand Up @@ -83,6 +89,10 @@ - (BOOL)isPrimaryDemo {
return CBCCatalogIsPrimaryDemoFromClass(_exampleClass);
}

- (BOOL)isPresentable {
return _isPresentable;
}

@end

@implementation CBCNodeListViewController
Expand Down Expand Up @@ -169,10 +179,19 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath

@end

CBCNode *CBCCreateNavigationTree(void) {
static CBCNode *CBCCreateTreeWithOnlyPresentable(BOOL onlyPresentable) {
NSArray *allClasses = CBCGetAllClasses();
NSArray *classes = CBCClassesRespondingToSelector(allClasses, @selector(catalogBreadcrumbs));

NSArray *breadcrumbClasses = CBCClassesRespondingToSelector(allClasses,
@selector(catalogBreadcrumbs));
NSArray *classes;
if (onlyPresentable) {
classes = [breadcrumbClasses filteredArrayUsingPredicate:
[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *bindings) {
return CBCCatalogIsPresentableFromClass(object);
}]];
} else {
classes = breadcrumbClasses;
}
CBCNode *tree = [[CBCNode alloc] initWithTitle:@"Root"];
for (Class aClass in classes) {
// Each example view controller defines its own "breadcrumbs".
Expand Down Expand Up @@ -201,6 +220,14 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
return tree;
}

CBCNode *CBCCreateNavigationTree(void) {
return CBCCreateTreeWithOnlyPresentable(NO);
}

CBCNode *CBCCreatePresentableNavigationTree(void) {
return CBCCreateTreeWithOnlyPresentable(YES);
}

void CBCAddNodeFromBreadCrumbs(CBCNode *tree, NSArray<NSString *> *breadCrumbs, Class aClass) {
// Walk down the navigation tree one breadcrumb at a time, creating nodes along the way.

Expand All @@ -218,6 +245,10 @@ void CBCAddNodeFromBreadCrumbs(CBCNode *tree, NSArray<NSString *> *breadCrumbs,

CBCNode *child = [[CBCNode alloc] initWithTitle:title];
[node addChild:child];
[node setIsPresentable:aClass];
if (CBCCatalogIsDebugLeaf(aClass)) {
tree.debugLeaf = child;
}
node = child;
}

Expand Down
12 changes: 12 additions & 0 deletions src/private/CBCRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ FOUNDATION_EXTERN NSArray<NSString *> *CBCCatalogBreadcrumbsFromClass(Class aCla
/** Invokes +catalogIsPrimaryDemo on the class and returns the BOOL value. */
FOUNDATION_EXTERN BOOL CBCCatalogIsPrimaryDemoFromClass(Class aClass);

/** Invokes +catalogIsPresentable on the class and returns the BOOL value. */
FOUNDATION_EXTERN BOOL CBCCatalogIsPresentableFromClass(Class aClass);

/** Invokes +catalogIsDebug on the class and returns the BOOL value. */
FOUNDATION_EXTERN BOOL CBCCatalogIsDebugLeaf(Class aClass);

#pragma mark Runtime enumeration

/** Returns all Objective-C and Swift classes available to the runtime. */
Expand All @@ -34,6 +40,12 @@ FOUNDATION_EXTERN NSArray<Class> *CBCGetAllClasses(void);
FOUNDATION_EXTERN NSArray<Class> *CBCClassesRespondingToSelector(NSArray<Class> *classes,
SEL selector);

/**
Internal helper method that allows invoking aClass with selector and puts
the return value in retValue.
*/
void CBCCatalogInvokeFromClassAndSelector(Class aClass, SEL selector, void *retValue);

#pragma mark UIViewController instantiation

/**
Expand Down
36 changes: 28 additions & 8 deletions src/private/CBCRuntime.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,40 @@

#pragma mark Primary demo check

BOOL CBCCatalogIsPrimaryDemoFromClass(Class aClass) {
BOOL isPrimaryDemo = NO;

if ([aClass respondsToSelector:@selector(catalogIsPrimaryDemo)]) {
void CBCCatalogInvokeFromClassAndSelector(Class aClass, SEL selector, void *retValue) {
if ([aClass respondsToSelector:selector]) {
NSMethodSignature *signature =
[aClass methodSignatureForSelector:@selector(catalogIsPrimaryDemo)];
[aClass methodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.selector = @selector(catalogIsPrimaryDemo);
invocation.selector = selector;
invocation.target = aClass;
[invocation invoke];
[invocation getReturnValue:&isPrimaryDemo];
[invocation getReturnValue:&retValue];
}
}

BOOL CBCCatalogIsPrimaryDemoFromClass(Class aClass) {
BOOL isPrimary = NO;
CBCCatalogInvokeFromClassAndSelector(aClass,
@selector(catalogIsPrimaryDemo),
&isPrimary);
return isPrimary;
}

BOOL CBCCatalogIsPresentableFromClass(Class aClass) {
BOOL isPresentable = NO;
CBCCatalogInvokeFromClassAndSelector(aClass,
@selector(catalogIsPresentable),
&isPresentable);
return isPresentable;
}

return isPrimaryDemo;
BOOL CBCCatalogIsDebugLeaf(Class aClass) {
BOOL isDebugLeaf = NO;
CBCCatalogInvokeFromClassAndSelector(aClass,
@selector(catalogIsDebug),
&isDebugLeaf);
return isDebugLeaf;
}

#pragma mark Runtime enumeration
Expand Down

0 comments on commit 67c6d97

Please sign in to comment.