Skip to content

Commit 6c44e44

Browse files
authored
added a new metadata property that will hold all the key/values for that node. Also code refactoring (#27)
1 parent 62f5b0b commit 6c44e44

File tree

6 files changed

+226
-166
lines changed

6 files changed

+226
-166
lines changed

example/Podfile.lock

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ EXTERNAL SOURCES:
2222
:path: components/Resistor
2323

2424
SPEC CHECKSUMS:
25-
CatalogByConvention: 1df2d770271921f668a99245c7c4c129e78941ee
26-
CatalogExamples: cafe3e4eae3abc948d96beb626657455c1dfb327
27-
CatalogUnitTests: b7a746f12abb31a905654521ee926ea007ab7275
28-
Resistor: 36a9ae98666be3b4f34d8133fad442fa87fdbce2
25+
CatalogByConvention: f4b95f8905470807a5022eabd1d3d9ce07f6a66f
26+
CatalogExamples: 7a95e6ea7befbd43c5ceb1427a9b161f6d8fc34e
27+
CatalogUnitTests: 2fbf7f2e894dd3777f11573a7a5314adb1e4fad7
28+
Resistor: a17e39cab5f42993c2b3ede22ce3829b707a9ac8
2929

3030
PODFILE CHECKSUM: bb59c09c71f8777bbe79af5ae920e3d58849ab41
3131

32-
COCOAPODS: 1.3.1
32+
COCOAPODS: 1.4.0

src/CBCCatalogExample.h

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,35 +25,47 @@
2525
*/
2626
@protocol CBCCatalogExample <NSObject>
2727

28+
/**
29+
Returns a dictionary with metaata information for the example.
30+
*/
31+
+ (nonnull NSDictionary<NSString *, NSObject *> *)catalogMetadata;
32+
33+
@optional
34+
2835
/** Return a list of breadcrumbs defining the navigation path taken to reach this example. */
29-
+ (nonnull NSArray<NSString *> *)catalogBreadcrumbs;
36+
+ (nonnull NSArray<NSString *> *)catalogBreadcrumbs
37+
__attribute__((deprecated("use catalogMetadata[CBCBreadcrumbs] instead.")));
3038

3139
/**
3240
Return a BOOL stating whether this example should be treated as the primary demo of the component.
3341
*/
34-
+ (BOOL)catalogIsPrimaryDemo;
42+
+ (BOOL)catalogIsPrimaryDemo
43+
__attribute__((deprecated("use catalogMetadata[CBCIsPrimaryDemo] instead.")));;
3544

3645
/**
3746
Return a BOOL stating whether this example is presentable and should be part of the catalog app.
3847
*/
39-
+ (BOOL)catalogIsPresentable;
48+
+ (BOOL)catalogIsPresentable
49+
__attribute__((deprecated("use catalogMetadata[CBCIsPresentable] instead.")));
4050

4151
/**
4252
Return a BOOL stating whether this example is in debug mode and should appear as the initial view controller.
4353
*/
44-
+ (BOOL)catalogIsDebug;
45-
46-
@optional
54+
+ (BOOL)catalogIsDebug
55+
__attribute__((deprecated("use catalogMetadata[CBCIsDebug] instead.")));
4756

4857
/**
4958
Return the name of a UIStoryboard from which the example's view controller should be instantiated.
5059
*/
51-
- (nonnull NSString *)catalogStoryboardName;
60+
- (nonnull NSString *)catalogStoryboardName
61+
__attribute__((deprecated("use catalogMetadata[CBCStoryboardName] instead.")));
5262

5363
/** Return a description of the example. */
54-
- (nonnull NSString *)catalogDescription;
64+
- (nonnull NSString *)catalogDescription
65+
__attribute__((deprecated("use catalogMetadata[CBCDescription] instead.")));
5566

5667
/** Return a link to related information or resources. */
57-
- (nonnull NSURL *)catalogRelatedInfo;
68+
- (nonnull NSURL *)catalogRelatedInfo
69+
__attribute__((deprecated("use catalogMetadata[CBCRelatedInfo] instead.")));
5870

5971
@end

src/CBCNodeListViewController.h

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,21 @@
1616

1717
#import <UIKit/UIKit.h>
1818

19+
/** This key represents a strings array of the breadcrumbs showing the hierarchy of the example */
20+
FOUNDATION_EXTERN NSString *_Nonnull const CBCBreadcrumbs;
21+
/** This key represents a boolean value if the example is for debugging */
22+
FOUNDATION_EXTERN NSString *_Nonnull const CBCIsDebug;
23+
/** This key represents a string for the description for the example */
24+
FOUNDATION_EXTERN NSString *_Nonnull const CBCDescription;
25+
/** This key represents a boolean value if to present the example in the Catalog app or not */
26+
FOUNDATION_EXTERN NSString *_Nonnull const CBCIsPresentable;
27+
/** This key represents a boolean value if the example is the primary demo */
28+
FOUNDATION_EXTERN NSString *_Nonnull const CBCIsPrimaryDemo;
29+
/** This key represents an NSURL value providing related info for the example */
30+
FOUNDATION_EXTERN NSString *_Nonnull const CBCRelatedInfo;
31+
/** This key represents a string value of the storyboard name for the example */
32+
FOUNDATION_EXTERN NSString *_Nonnull const CBCStoryboardName;
33+
1934
@class CBCNode;
2035

2136
/**
@@ -69,9 +84,6 @@ FOUNDATION_EXTERN CBCNode *_Nonnull CBCCreatePresentableNavigationTree(void);
6984
/** The title for this node. */
7085
@property(nonatomic, copy, nonnull, readonly) NSString *title;
7186

72-
/** The description for this node. */
73-
@property(nonatomic, copy, nonnull, readonly) NSString *nodeDescription;
74-
7587
/** The children of this node. */
7688
@property(nonatomic, strong, nonnull) NSArray<CBCNode *> *children;
7789

@@ -83,6 +95,13 @@ FOUNDATION_EXTERN CBCNode *_Nonnull CBCCreatePresentableNavigationTree(void);
8395
*/
8496
@property(nonatomic, strong, nullable) CBCNode *debugLeaf;
8597

98+
/**
99+
This NSDictionary holds all the metadata related to this CBCNode.
100+
If it is an example noe, a primary demo, related info,
101+
if presentable in Catalog, etc.
102+
*/
103+
@property(nonatomic, strong, nonnull) NSDictionary *metadata;
104+
86105
/** Returns YES if this is an example node. */
87106
- (BOOL)isExample;
88107

@@ -111,7 +130,7 @@ FOUNDATION_EXTERN CBCNode *_Nonnull CBCCreatePresentableNavigationTree(void);
111130
112131
Check that isExample returns YES before invoking.
113132
*/
114-
- (nonnull NSString *)exampleDescription;
133+
- (nullable NSString *)exampleDescription;
115134

116135
/** Returns a link to related information for the example. */
117136
- (nullable NSURL *)exampleRelatedInfo;

src/CBCNodeListViewController.m

Lines changed: 84 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,21 @@
1919
#import "CBCCatalogExample.h"
2020
#import "private/CBCRuntime.h"
2121

22-
void CBCAddNodeFromBreadCrumbs(CBCNode *tree, NSArray<NSString *> *breadCrumbs, Class aClass);
22+
@interface CBCNode()
23+
@property(nonatomic, strong, nullable) NSMutableDictionary *map;
24+
@property(nonatomic, strong, nullable) Class exampleClass;
25+
@end
2326

2427
@implementation CBCNode {
25-
NSMutableDictionary *_map;
2628
NSMutableArray *_children;
27-
Class _exampleClass;
28-
BOOL _isPresentable;
2929
}
3030

3131
- (instancetype)initWithTitle:(NSString *)title {
3232
self = [super init];
3333
if (self) {
3434
_title = [title copy];
35-
_map = [NSMutableDictionary dictionary];
35+
self.map = [NSMutableDictionary dictionary];
3636
_children = [NSMutableArray array];
37-
_isPresentable = NO;
3837
CBCFixViewDebuggingIfNeeded();
3938
}
4039
return self;
@@ -45,72 +44,75 @@ - (NSComparisonResult)compare:(CBCNode *)otherObject {
4544
}
4645

4746
- (void)addChild:(CBCNode *)child {
48-
_map[child.title] = child;
47+
self.map[child.title] = child;
4948
[_children addObject:child];
5049
}
5150

52-
- (NSDictionary *)map {
53-
return _map;
54-
}
55-
56-
- (void)setExampleClass:(Class)exampleClass {
57-
_exampleClass = exampleClass;
58-
}
59-
60-
- (void)setIsPresentable:(Class)exampleClass {
61-
_isPresentable = CBCCatalogIsPresentableFromClass(exampleClass);
62-
}
63-
6451
- (void)finalizeNode {
6552
_children = [[_children sortedArrayUsingSelector:@selector(compare:)] mutableCopy];
6653
}
6754

6855
#pragma mark Public
6956

7057
- (BOOL)isExample {
71-
return _exampleClass != nil;
58+
return self.exampleClass != nil;
7259
}
7360

7461
- (NSString *)exampleViewControllerName {
62+
NSAssert(self.exampleClass != nil, @"This node has no associated example.");
7563
return NSStringFromClass(_exampleClass);
7664
}
7765

7866
- (UIViewController *)createExampleViewController {
79-
NSAssert(_exampleClass != nil, @"This node has no associated example.");
80-
return CBCViewControllerFromClass(_exampleClass);
67+
NSAssert(self.exampleClass != nil, @"This node has no associated example.");
68+
return CBCViewControllerFromClass(self.exampleClass, self.metadata);
8169
}
8270

8371
- (NSString *)exampleDescription {
84-
NSAssert(_exampleClass != nil, @"This node has no associated example.");
85-
return CBCDescriptionFromClass(_exampleClass);
72+
NSString *description = [self.metadata objectForKey:CBCDescription];
73+
if (description != nil && [description isKindOfClass:[NSString class]]) {
74+
return description;
75+
}
76+
return nil;
8677
}
8778

8879
- (NSURL *)exampleRelatedInfo {
89-
NSAssert(_exampleClass != nil, @"This node has no associated example.");
90-
return CBCRelatedInfoFromClass(_exampleClass);
80+
NSURL *relatedInfo = [self.metadata objectForKey:CBCRelatedInfo];
81+
if (relatedInfo != nil && [relatedInfo isKindOfClass:[NSURL class]]) {
82+
return relatedInfo;
83+
}
84+
return nil;
9185
}
9286

9387
- (BOOL)isPrimaryDemo {
94-
return CBCCatalogIsPrimaryDemoFromClass(_exampleClass);
88+
id isPrimaryDemo;
89+
if ((isPrimaryDemo = [self.metadata objectForKey:CBCIsPrimaryDemo]) != nil) {
90+
return [isPrimaryDemo boolValue];
91+
}
92+
return NO;
9593
}
9694

9795
- (BOOL)isPresentable {
98-
return _isPresentable;
96+
id isPresentable;
97+
if ((isPresentable = [self.metadata objectForKey:CBCIsPresentable]) != nil) {
98+
return [isPresentable boolValue];
99+
}
100+
return NO;
99101
}
100102

101103
@end
102104

103105
@implementation CBCNodeListViewController
104106

105107
- (instancetype)initWithNode:(CBCNode *)node {
106-
NSAssert(!_node.isExample, @"%@ cannot represent example nodes.",
108+
NSAssert(!self.node.isExample, @"%@ cannot represent example nodes.",
107109
NSStringFromClass([self class]));
108110

109111
self = [super initWithNibName:nil bundle:nil];
110112
if (self) {
111113
_node = node;
112114

113-
self.title = _node.title;
115+
self.title = self.node.title;
114116
}
115117
return self;
116118
}
@@ -154,7 +156,7 @@ - (void)viewDidAppear:(BOOL)animated {
154156
#pragma mark - UITableViewDataSource
155157

156158
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
157-
return (NSInteger)[_node.children count];
159+
return (NSInteger)[self.node.children count];
158160
}
159161

160162
- (UITableViewCell *)tableView:(UITableView *)tableView
@@ -164,15 +166,15 @@ - (UITableViewCell *)tableView:(UITableView *)tableView
164166
cell =
165167
[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
166168
}
167-
cell.textLabel.text = [_node.children[(NSUInteger)indexPath.row] title];
169+
cell.textLabel.text = [self.node.children[(NSUInteger)indexPath.row] title];
168170
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
169171
return cell;
170172
}
171173

172174
#pragma mark - UITableViewDelegate
173175

174176
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
175-
CBCNode *node = _node.children[(NSUInteger)indexPath.row];
177+
CBCNode *node = self.node.children[(NSUInteger)indexPath.row];
176178
UIViewController *viewController = nil;
177179
if ([node isExample]) {
178180
viewController = [node createExampleViewController];
@@ -184,30 +186,61 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
184186

185187
@end
186188

187-
static CBCNode *CBCCreateTreeWithOnlyPresentable(BOOL onlyPresentable) {
188-
NSArray *allClasses = CBCGetAllClasses();
189-
NSArray *breadcrumbClasses = CBCClassesRespondingToSelector(allClasses,
190-
@selector(catalogBreadcrumbs));
191-
NSArray *classes;
192-
if (onlyPresentable) {
193-
classes = [breadcrumbClasses filteredArrayUsingPredicate:
194-
[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *bindings) {
195-
return CBCCatalogIsPresentableFromClass(object);
196-
}]];
197-
} else {
198-
classes = breadcrumbClasses;
189+
static void CBCAddNodeFromBreadCrumbs(CBCNode *tree,
190+
NSArray<NSString *> *breadCrumbs,
191+
Class aClass,
192+
NSDictionary *metadata) {
193+
// Walk down the navigation tree one breadcrumb at a time, creating nodes along the way.
194+
195+
CBCNode *node = tree;
196+
for (NSUInteger ix = 0; ix < [breadCrumbs count]; ++ix) {
197+
NSString *title = breadCrumbs[ix];
198+
BOOL isLastCrumb = ix == [breadCrumbs count] - 1;
199+
200+
// Don't walk the last crumb
201+
if (node.map[title] && !isLastCrumb) {
202+
node = node.map[title];
203+
continue;
204+
}
205+
206+
CBCNode *child = [[CBCNode alloc] initWithTitle:title];
207+
[node addChild:child];
208+
child.metadata = metadata;
209+
if ([[child.metadata objectForKey:CBCIsPrimaryDemo] boolValue] == YES) {
210+
node.metadata = child.metadata;
211+
}
212+
if ([[child.metadata objectForKey:CBCIsDebug] boolValue] == YES) {
213+
tree.debugLeaf = child;
214+
}
215+
node = child;
199216
}
200-
CBCNode *tree = [[CBCNode alloc] initWithTitle:@"Root"];
201-
for (Class aClass in classes) {
202-
// Each example view controller defines its own "breadcrumbs".
203217

204-
NSArray *breadCrumbs = CBCCatalogBreadcrumbsFromClass(aClass);
218+
node.exampleClass = aClass;
219+
}
220+
221+
static CBCNode *CBCCreateTreeWithOnlyPresentable(BOOL onlyPresentable) {
222+
NSArray *allClasses = CBCGetAllCompatibleClasses();
223+
NSArray *filteredClasses = [allClasses filteredArrayUsingPredicate:
224+
[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *bindings) {
225+
NSDictionary *metadata = CBCCatalogMetadataFromClass(object);
226+
id breadcrumbs = [metadata objectForKey:CBCBreadcrumbs];
227+
BOOL validObject = breadcrumbs != nil && [breadcrumbs isKindOfClass:[NSArray class]];
228+
if (onlyPresentable) {
229+
validObject &= ([[metadata objectForKey:CBCIsPresentable] boolValue] == YES);
230+
}
231+
return validObject;
232+
}]];
205233

234+
CBCNode *tree = [[CBCNode alloc] initWithTitle:@"Root"];
235+
for (Class aClass in filteredClasses) {
236+
// Each example view controller defines its own breadcrumbs (metadata[CBCBreadcrumbs]).
237+
NSDictionary *metadata = CBCCatalogMetadataFromClass(aClass);
238+
NSArray *breadCrumbs = [metadata objectForKey:CBCBreadcrumbs];
206239
if ([[breadCrumbs firstObject] isKindOfClass:[NSString class]]) {
207-
CBCAddNodeFromBreadCrumbs(tree, breadCrumbs, aClass);
240+
CBCAddNodeFromBreadCrumbs(tree, breadCrumbs, aClass, metadata);
208241
} else if ([[breadCrumbs firstObject] isKindOfClass:[NSArray class]]) {
209242
for (NSArray<NSString *> *parallelBreadCrumb in breadCrumbs) {
210-
CBCAddNodeFromBreadCrumbs(tree, parallelBreadCrumb, aClass);
243+
CBCAddNodeFromBreadCrumbs(tree, parallelBreadCrumb, aClass, metadata);
211244
}
212245
}
213246
}
@@ -232,30 +265,3 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
232265
CBCNode *CBCCreatePresentableNavigationTree(void) {
233266
return CBCCreateTreeWithOnlyPresentable(YES);
234267
}
235-
236-
void CBCAddNodeFromBreadCrumbs(CBCNode *tree, NSArray<NSString *> *breadCrumbs, Class aClass) {
237-
// Walk down the navigation tree one breadcrumb at a time, creating nodes along the way.
238-
239-
CBCNode *node = tree;
240-
for (NSUInteger ix = 0; ix < [breadCrumbs count]; ++ix) {
241-
NSString *title = breadCrumbs[ix];
242-
BOOL isLastCrumb = ix == [breadCrumbs count] - 1;
243-
244-
// Don't walk the last crumb
245-
246-
if (node.map[title] && !isLastCrumb) {
247-
node = node.map[title];
248-
continue;
249-
}
250-
251-
CBCNode *child = [[CBCNode alloc] initWithTitle:title];
252-
[node addChild:child];
253-
[node setIsPresentable:aClass];
254-
if (CBCCatalogIsDebugLeaf(aClass)) {
255-
tree.debugLeaf = child;
256-
}
257-
node = child;
258-
}
259-
260-
node.exampleClass = aClass;
261-
}

0 commit comments

Comments
 (0)