Skip to content

Commit

Permalink
Fixed cross reference to members and objects when embedded or followe…
Browse files Browse the repository at this point in the history
…d by punctuation. Closes #33.

appledoc failed to detect cross references if object or member names were surrounded with parenthesis or followed by punctuation. The problem was twofold: to properly handle such cases, matching regex expressions had to be modified a bit plus detection method has to return proper range of detected cross ref so that the remaining text can be properly handled.

Note that similar to #35, the result is all text is properly generated but there are extra spaces. This is going to be covered with #34.
  • Loading branch information
tomaz committed Jan 7, 2011
1 parent 452c14b commit 4428891
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 41 deletions.
5 changes: 4 additions & 1 deletion Application/GBCommentComponentsProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,10 @@
/** Returns the regex used for matching (possible) local member cross reference with capture 1 containing member name. */
@property (readonly) NSString *localMemberCrossReferenceRegex;

/** Returns the regex used for matching (possible) object cross reference with capture 1 containing object name. */
/** Returns the regex used for matching (possible) category cross reference with capture 1 containing category name. */
@property (readonly) NSString *categoryCrossReferenceRegex;

/** Returns the regex used for matching (possible) class or protocol cross reference with capture 1 containing object name. */
@property (readonly) NSString *objectCrossReferenceRegex;

/** Returns the regex used for matching URL cross reference with caption 1 contining the URL itself. */
Expand Down
17 changes: 8 additions & 9 deletions Application/GBCommentComponentsProvider.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ - (NSString *)argumentsCommonRegex;
- (NSString *)exampleRegexWithoutFlags;
- (NSString *)descriptionCaptureRegexForKeyword:(NSString *)keyword;
- (NSString *)nameDescriptionCaptureRegexForKeyword:(NSString *)keyword;
- (NSString *)crossReferenceRegexByEmbeddingRegex:(NSString *)regex;

@end

Expand Down Expand Up @@ -114,19 +113,23 @@ - (NSString *)crossReferenceRegex {

- (NSString *)remoteMemberCrossReferenceRegex {
// +[Class member] or -[Class member] or simply [Class member].
return [self crossReferenceRegexByEmbeddingRegex:@"[+-]?\\[(\\S+)\\s+(\\S+)\\]"];
return @"<?[+-]?\\[(\\S+)\\s+(\\S+)\\]>?";
}

- (NSString *)localMemberCrossReferenceRegex {
return [self crossReferenceRegexByEmbeddingRegex:@"([^>\\s]+)"];
return @"<?([^>,.;()\\s]+)>?";
}

- (NSString *)categoryCrossReferenceRegex {
return @"<?([^(][^>,.:;)\\s]+\\))>?";
}

- (NSString *)objectCrossReferenceRegex {
return [self crossReferenceRegexByEmbeddingRegex:@"([^>\\s]+)"];
return @"<?([^>,.:;()\\s]+)>?";
}

- (NSString *)urlCrossReferenceRegex {
return [self crossReferenceRegexByEmbeddingRegex:@"(\\b(?:mailto\\:|(?:https?|ftps?|news|rss|file)\\://)[a-zA-Z0-9@:\\-.]+(?::(\\d+))?(?:(?:/[a-zA-Z0-9\\-._?,'+\\&%$=~*!():@\\\\]*)+)?)"];
return @"<?(\\b(?:mailto\\:|(?:https?|ftps?|news|rss|file)\\://)[a-zA-Z0-9@:\\-.]+(?::(\\d+))?(?:(?:/[a-zA-Z0-9\\-._?,'+\\&%$=~*!():@\\\\]*)+)?)>?";
}

#pragma mark Helper methods
Expand All @@ -139,8 +142,4 @@ - (NSString *)nameDescriptionCaptureRegexForKeyword:(NSString *)keyword {
return [NSString stringWithFormat:@"^\\s*\\S%@\\s+([^\\s]+)\\s+(?s:(.*))", keyword];
}

- (NSString *)crossReferenceRegexByEmbeddingRegex:(NSString *)regex {
return [NSString stringWithFormat:@"<?%@>?", regex];
}

@end
64 changes: 37 additions & 27 deletions Processing/GBCommentsProcessor.m
Original file line number Diff line number Diff line change
Expand Up @@ -510,10 +510,12 @@ - (NSArray *)paragraphSimpleLinkItemsFromString:(NSString *)string {
NSRange range;
GBParagraphLinkItem *item = [self simpleLinkItemFromString:word matchRange:&range];
if (item) {
if (range.location > 0) [staticText addObject:[word substringToIndex:range.location]];
if (range.location > 0 && range.location != NSNotFound) [staticText addObject:[word substringToIndex:range.location]];
GBCREATE_TEXT_ITEM;
NSUInteger last = range.location + range.length;
if (last < [word length]) [staticText addObject:[word substringFromIndex:last]];
if (range.location != NSNotFound) {
NSUInteger last = range.location + range.length;
if (last < [word length]) [staticText addObject:[word substringFromIndex:last]];
}
[result addObject:item];
foundLinks = YES;
return;
Expand Down Expand Up @@ -665,58 +667,66 @@ - (GBParagraphLinkItem *)remoteMemberLinkItemFromString:(NSString *)string match
}

- (GBParagraphLinkItem *)simpleLinkItemFromString:(NSString *)string matchRange:(NSRange *)range {
// Returns URL, local member or another known object link item or nil if the string doesn't represent the item.
// Returns URL, local member or another known object link item or nil if the string doesn't represent the item. Note that we get all capture components, where the first entry is full text, including optional <> and the second is only the inner part. If there is no <>, both have the same value. We need to consider both options to properly handle range of the link text within the string!
GBCommentComponentsProvider *provider = self.settings.commentComponents;
GBModelBase *hrefSourceObject = (GBModelBase *)self.currentContext;

// Test for URL reference. Note that we should return proper range accounting for optional <>!
NSString *url = [string stringByMatching:provider.urlCrossReferenceRegex capture:1];
if (url) {
NSArray *urls = [string captureComponentsMatchedByRegex:provider.urlCrossReferenceRegex];
if ([urls count] > 1) {
NSString *url = [urls objectAtIndex:1];
GBParagraphLinkItem *item = [GBParagraphLinkItem paragraphItemWithStringValue:url];
item.href = url;
if (range) {
NSString *full = [string stringByMatching:provider.urlCrossReferenceRegex capture:0];
*range = [string rangeOfString:full];
}
if (range) *range = [string rangeOfString:[urls objectAtIndex:0]];
return item;
}

// Test for local member reference (only if current context is given).
if (self.currentContext) {
NSString *selector = [string stringByMatching:provider.localMemberCrossReferenceRegex capture:1];
if (selector) {
NSArray *selectors = [string captureComponentsMatchedByRegex:provider.localMemberCrossReferenceRegex];
if ([selectors count] > 1) {
NSString *selector = [selectors objectAtIndex:1];
GBMethodData *method = [self.currentContext.methods methodBySelector:selector];
if (method) {
GBParagraphLinkItem *item = [GBParagraphLinkItem paragraphItemWithStringValue:selector];
item.href = [self.settings htmlReferenceForObject:method fromSource:hrefSourceObject];
item.context = self.currentContext;
item.member = method;
item.isLocal = YES;
if (range) *range = NSMakeRange(0, [string length]);
if (range) *range = [string rangeOfString:[selectors objectAtIndex:0]];
return item;
}
}
}

// Test for local or remote object reference.
NSString *objectName = [string stringByMatching:provider.objectCrossReferenceRegex capture:1];
if (objectName) {
GBClassData *class = [self.store classWithName:objectName];
if (class) {
GBParagraphLinkItem *item = [GBParagraphLinkItem paragraphItemWithStringValue:class.nameOfClass];
item.href = [self.settings htmlReferenceForObject:class fromSource:hrefSourceObject];
item.context = class;
item.isLocal = (class == self.currentContext);
if (range) *range = NSMakeRange(0, [string length]);
return item;
}
// Test for local or remote category reference.
NSArray *names = [string captureComponentsMatchedByRegex:provider.categoryCrossReferenceRegex];
if ([names count] > 1) {
NSString *objectName = [names objectAtIndex:1];
NSString *embeddedName = [names objectAtIndex:0];
GBCategoryData *category = [self.store categoryWithName:objectName];
if (category) {
GBParagraphLinkItem *item = [GBParagraphLinkItem paragraphItemWithStringValue:category.idOfCategory];
item.href = [self.settings htmlReferenceForObject:category fromSource:hrefSourceObject];
item.context = category;
item.isLocal = (category == self.currentContext);
if (range) *range = NSMakeRange(0, [string length]);
if (range) *range = [string rangeOfString:embeddedName];
return item;
}
}

// Test for local or remote class or protocol reference.
names = [string captureComponentsMatchedByRegex:provider.objectCrossReferenceRegex];
if ([names count] > 1) {
NSString *objectName = [names objectAtIndex:1];
NSString *embeddedName = [names objectAtIndex:0];
GBClassData *class = [self.store classWithName:objectName];
if (class) {
GBParagraphLinkItem *item = [GBParagraphLinkItem paragraphItemWithStringValue:class.nameOfClass];
item.href = [self.settings htmlReferenceForObject:class fromSource:hrefSourceObject];
item.context = class;
item.isLocal = (class == self.currentContext);
if (range) *range = [string rangeOfString:embeddedName];
return item;
}
GBProtocolData *protocol = [self.store protocolWithName:objectName];
Expand All @@ -725,7 +735,7 @@ - (GBParagraphLinkItem *)simpleLinkItemFromString:(NSString *)string matchRange:
item.href = [self.settings htmlReferenceForObject:protocol fromSource:hrefSourceObject];
item.context = protocol;
item.isLocal = (protocol == self.currentContext);
if (range) *range = NSMakeRange(0, [string length]);
if (range) *range = [string rangeOfString:embeddedName];
return item;
}
}
Expand Down
Loading

0 comments on commit 4428891

Please sign in to comment.