Skip to content

Commit

Permalink
Implemented example sections processing.
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaz committed Sep 2, 2010
1 parent e6c6782 commit f54495f
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 33 deletions.
6 changes: 6 additions & 0 deletions Application/GBCommentComponentsProvider.h
Expand Up @@ -44,6 +44,12 @@
/** Returns the regex used for matching bug section with capture 1 containing description. */ /** Returns the regex used for matching bug section with capture 1 containing description. */
@property (readonly) NSString *bugSectionRegex; @property (readonly) NSString *bugSectionRegex;


/** Returns the regex used for matching example section with capture 1 containing example text. */
@property (readonly) NSString *exampleSectionRegex;

/** Returns the regex used for matching example lines with capture 1 containing example lines texts. */
@property (readonly) NSString *exampleLinesRegex;

/** Returns the regex used for matching method parameter description with capture 1 containing parameter name and capture 2 description. */ /** Returns the regex used for matching method parameter description with capture 1 containing parameter name and capture 2 description. */
@property (readonly) NSString *parameterDescriptionRegex; @property (readonly) NSString *parameterDescriptionRegex;


Expand Down
33 changes: 23 additions & 10 deletions Application/GBCommentComponentsProvider.m
Expand Up @@ -18,8 +18,9 @@


@interface GBCommentComponentsProvider () @interface GBCommentComponentsProvider ()


- (NSString *)singleCaptureRegexForKeyword:(NSString *)keyword; - (NSString *)exampleRegexWithoutFlags;
- (NSString *)doubleCaptureRegexForKeyword:(NSString *)keyword; - (NSString *)descriptionCaptureRegexForKeyword:(NSString *)keyword;
- (NSString *)nameDescriptionCaptureRegexForKeyword:(NSString *)keyword;


@end @end


Expand Down Expand Up @@ -52,36 +53,48 @@ - (NSString *)unorderedListPrefixRegex {
} }


- (NSString *)warningSectionRegex { - (NSString *)warningSectionRegex {
GBRETURN_ON_DEMAND([self singleCaptureRegexForKeyword:@"warning"]); GBRETURN_ON_DEMAND([self descriptionCaptureRegexForKeyword:@"warning"]);
} }


- (NSString *)bugSectionRegex { - (NSString *)bugSectionRegex {
GBRETURN_ON_DEMAND([self singleCaptureRegexForKeyword:@"bug"]); GBRETURN_ON_DEMAND([self descriptionCaptureRegexForKeyword:@"bug"]);
}

- (NSString *)exampleSectionRegex {
GBRETURN_ON_DEMAND(([NSString stringWithFormat:@"(?s:%@)", [self exampleRegexWithoutFlags]]));
}

- (NSString *)exampleLinesRegex {
GBRETURN_ON_DEMAND(([NSString stringWithFormat:@"(?m:%@)", [self exampleRegexWithoutFlags]]));
}

- (NSString *)exampleRegexWithoutFlags {
GBRETURN_ON_DEMAND(@"^[ ]*\\t(.*)");
} }


- (NSString *)parameterDescriptionRegex { - (NSString *)parameterDescriptionRegex {
GBRETURN_ON_DEMAND([self doubleCaptureRegexForKeyword:@"param"]); GBRETURN_ON_DEMAND([self nameDescriptionCaptureRegexForKeyword:@"param"]);
} }


- (NSString *)returnDescriptionRegex { - (NSString *)returnDescriptionRegex {
GBRETURN_ON_DEMAND([self singleCaptureRegexForKeyword:@"return"]); GBRETURN_ON_DEMAND([self descriptionCaptureRegexForKeyword:@"return"]);
} }


- (NSString *)exceptionDescriptionRegex { - (NSString *)exceptionDescriptionRegex {
GBRETURN_ON_DEMAND([self doubleCaptureRegexForKeyword:@"exception"]); GBRETURN_ON_DEMAND([self nameDescriptionCaptureRegexForKeyword:@"exception"]);
} }


- (NSString *)crossReferenceRegex { - (NSString *)crossReferenceRegex {
GBRETURN_ON_DEMAND([self singleCaptureRegexForKeyword:@"(sa|see)"]); GBRETURN_ON_DEMAND([self descriptionCaptureRegexForKeyword:@"(sa|see)"]);
} }


#pragma mark Helper methods #pragma mark Helper methods


- (NSString *)singleCaptureRegexForKeyword:(NSString *)keyword { - (NSString *)descriptionCaptureRegexForKeyword:(NSString *)keyword {
return [NSString stringWithFormat:@"^\\s*.%@\\s+(?s:(.*))", keyword]; return [NSString stringWithFormat:@"^\\s*.%@\\s+(?s:(.*))", keyword];
} }


- (NSString *)doubleCaptureRegexForKeyword:(NSString *)keyword { - (NSString *)nameDescriptionCaptureRegexForKeyword:(NSString *)keyword {
return [NSString stringWithFormat:@"^\\s*.%@\\s+([^\\s]+)\\s+(?s:(.*))", keyword]; return [NSString stringWithFormat:@"^\\s*.%@\\s+([^\\s]+)\\s+(?s:(.*))", keyword];
} }


Expand Down
77 changes: 55 additions & 22 deletions GBCommentsProcessor.m
Expand Up @@ -19,10 +19,12 @@ - (void)registerOrderedListFromString:(NSString *)string toParagraph:(GBCommentP
- (void)registerListFromString:(NSString *)string ordered:(BOOL)ordered usingRegex:(NSString *)regex toParagraph:(GBCommentParagraph *)paragraph; - (void)registerListFromString:(NSString *)string ordered:(BOOL)ordered usingRegex:(NSString *)regex toParagraph:(GBCommentParagraph *)paragraph;
- (void)registerWarningFromString:(NSString *)string toParagraph:(GBCommentParagraph *)paragraph; - (void)registerWarningFromString:(NSString *)string toParagraph:(GBCommentParagraph *)paragraph;
- (void)registerBugFromString:(NSString *)string toParagraph:(GBCommentParagraph *)paragraph; - (void)registerBugFromString:(NSString *)string toParagraph:(GBCommentParagraph *)paragraph;
- (void)registerExampleFromString:(NSString *)string toParagraph:(GBCommentParagraph *)paragraph;
- (void)registerSpecialFromString:(NSString *)string type:(GBSpecialItemType)type usingRegex:(NSString *)regex toParagraph:(GBCommentParagraph *)paragraph; - (void)registerSpecialFromString:(NSString *)string type:(GBSpecialItemType)type usingRegex:(NSString *)regex toParagraph:(GBCommentParagraph *)paragraph;
- (void)registerTextFromString:(NSString *)string toParagraph:(GBCommentParagraph *)paragraph; - (void)registerTextFromString:(NSString *)string toParagraph:(GBCommentParagraph *)paragraph;
- (NSArray *)componentsSeparatedByEmptyLinesFromString:(NSString *)string; - (NSArray *)componentsSeparatedByEmptyLinesFromString:(NSString *)string;
- (NSArray *)componentsSeparatedByNewLinesFromString:(NSString *)string; - (NSArray *)componentsSeparatedByNewLinesFromString:(NSString *)string;
@property (retain) NSString *newLinesRegexSymbols;
@property (retain) NSString *spaceAndNewLineTrimRegex; @property (retain) NSString *spaceAndNewLineTrimRegex;
@property (retain) id<GBApplicationSettingsProviding> settings; @property (retain) id<GBApplicationSettingsProviding> settings;
@property (retain) id<GBStoreProviding> store; @property (retain) id<GBStoreProviding> store;
Expand All @@ -45,8 +47,8 @@ - (id)initWithSettingsProvider:(id)settingsProvider {
GBLogDebug(@"Initializing comments processor with settings provider %@...", settingsProvider); GBLogDebug(@"Initializing comments processor with settings provider %@...", settingsProvider);
self = [super init]; self = [super init];
if (self) { if (self) {
NSString *spaceAndNewLineRegex = [NSString stringWithUTF8String:"(?:\\r\n|[ \n\\v\\f\\r\302\205\\p{Zl}\\p{Zp}])+"]; self.newLinesRegexSymbols = [NSString stringWithUTF8String:"(?:\\r\n|[ \n\\v\\f\\r\302\205\\p{Zl}\\p{Zp}])+"];
self.spaceAndNewLineTrimRegex = [NSString stringWithFormat:@"^%@|%@$", spaceAndNewLineRegex, spaceAndNewLineRegex]; self.spaceAndNewLineTrimRegex = [NSString stringWithFormat:@"^%1$@|%1$@$", self.newLinesRegexSymbols];
self.settings = settingsProvider; self.settings = settingsProvider;
} }
return self; return self;
Expand All @@ -70,27 +72,34 @@ - (void)processComment:(GBComment *)comment withStore:(id)store {
NSArray *components = [self componentsSeparatedByEmptyLinesFromString:[comment stringValue]]; NSArray *components = [self componentsSeparatedByEmptyLinesFromString:[comment stringValue]];
__block GBCommentParagraph *currentParagraph = nil; __block GBCommentParagraph *currentParagraph = nil;
[components enumerateObjectsUsingBlock:^(NSString *component, NSUInteger idx, BOOL *stop) { [components enumerateObjectsUsingBlock:^(NSString *component, NSUInteger idx, BOOL *stop) {
// Match known parts. // As most components are given with preceeding new line, we should remove it to get cleaner testing.
if ([component isMatchedByRegex:componizer.unorderedListRegex]) { NSString *trimmed = [component stringByReplacingOccurrencesOfRegex:self.spaceAndNewLineTrimRegex withString:@""];
GBRegister([self registerUnorderedListFromString:component toParagraph:currentParagraph]);
// Match known parts. Note that order is important for certain items (lists must be processed before examples for example).
if ([trimmed isMatchedByRegex:componizer.unorderedListRegex]) {
GBRegister([self registerUnorderedListFromString:trimmed toParagraph:currentParagraph]);
return;
}
if ([trimmed isMatchedByRegex:componizer.orderedListRegex]) {
GBRegister([self registerOrderedListFromString:trimmed toParagraph:currentParagraph]);
return; return;
} }
if ([component isMatchedByRegex:componizer.orderedListRegex]) { if ([trimmed isMatchedByRegex:componizer.warningSectionRegex]) {
GBRegister([self registerOrderedListFromString:component toParagraph:currentParagraph]); GBRegister([self registerWarningFromString:trimmed toParagraph:currentParagraph]);
return; return;
} }
if ([component isMatchedByRegex:componizer.warningSectionRegex]) { if ([trimmed isMatchedByRegex:componizer.bugSectionRegex]) {
GBRegister([self registerWarningFromString:component toParagraph:currentParagraph]); GBRegister([self registerBugFromString:trimmed toParagraph:currentParagraph]);
return; return;
} }
if ([component isMatchedByRegex:componizer.bugSectionRegex]) { if ([trimmed isMatchedByRegex:componizer.exampleSectionRegex]) {
GBRegister([self registerBugFromString:component toParagraph:currentParagraph]); GBRegister([self registerExampleFromString:trimmed toParagraph:currentParagraph]);
return; return;
} }


// If no other match was found, this is simple text, so start new paragraph. // If no other match was found, this is simple text, so start new paragraph.
currentParagraph = [GBCommentParagraph paragraph]; currentParagraph = [GBCommentParagraph paragraph];
[self registerTextFromString:component toParagraph:currentParagraph]; [self registerTextFromString:trimmed toParagraph:currentParagraph];
[comment registerParagraph:currentParagraph]; [comment registerParagraph:currentParagraph];
}]; }];
} }
Expand All @@ -106,16 +115,14 @@ - (void)registerOrderedListFromString:(NSString *)string toParagraph:(GBCommentP
} }


- (void)registerListFromString:(NSString *)string ordered:(BOOL)ordered usingRegex:(NSString *)regex toParagraph:(GBCommentParagraph *)paragraph { - (void)registerListFromString:(NSString *)string ordered:(BOOL)ordered usingRegex:(NSString *)regex toParagraph:(GBCommentParagraph *)paragraph {
// Sometimes we can get newlines and spaces before or after the component, so remove them first, then use trimmed string as list's string value. GBParagraphListItem *item = [GBParagraphListItem paragraphItemWithStringValue:string];
NSString *trimmed = [string stringByReplacingOccurrencesOfRegex:self.spaceAndNewLineTrimRegex withString:@""];
GBParagraphListItem *item = [GBParagraphListItem paragraphItemWithStringValue:trimmed];
item.isOrdered = ordered; item.isOrdered = ordered;


// Split the block of all list items to individual items, then process and register each one. // Split the block of all list items to individual items, then process and register each one.
NSArray *items = [trimmed componentsSeparatedByRegex:regex]; NSArray *items = [string componentsSeparatedByRegex:regex];
[items enumerateObjectsUsingBlock:^(NSString *description, NSUInteger idx, BOOL *stop) { [items enumerateObjectsUsingBlock:^(NSString *description, NSUInteger idx, BOOL *stop) {
if ([description length] == 0) { if ([description length] == 0) {
GBLogWarn(@"%ld. item has empty description for list:\n%@", idx, trimmed); GBLogWarn(@"%ld. item has empty description for list:\n%@", idx, string);
return; return;
} }
GBCommentParagraph *paragraph = [GBCommentParagraph paragraph]; GBCommentParagraph *paragraph = [GBCommentParagraph paragraph];
Expand All @@ -137,17 +144,41 @@ - (void)registerBugFromString:(NSString *)string toParagraph:(GBCommentParagraph
[self registerSpecialFromString:string type:GBSpecialItemTypeBug usingRegex:self.settings.commentComponents.bugSectionRegex toParagraph:paragraph]; [self registerSpecialFromString:string type:GBSpecialItemTypeBug usingRegex:self.settings.commentComponents.bugSectionRegex toParagraph:paragraph];
} }


- (void)registerExampleFromString:(NSString *)string toParagraph:(GBCommentParagraph *)paragraph {
// Get the description from the string. If empty, warn and exit.
NSArray *lines = [string componentsMatchedByRegex:self.settings.commentComponents.exampleLinesRegex capture:1];
NSMutableString *example = [NSMutableString stringWithCapacity:[string length]];
[lines enumerateObjectsUsingBlock:^(NSString *line, NSUInteger idx, BOOL *stop) {
if ([example length] > 0) [example appendString:@"\n"];
[example appendString:line];
}];

// Warn if empty example was found.
if ([example length] == 0) {
GBLogWarn(@"Empty example section found!");
return;
}

// Prepare paragraph item and process the text.
GBParagraphSpecialItem *item = [GBParagraphSpecialItem specialItemWithType:GBSpecialItemTypeExample stringValue:string];
GBCommentParagraph *para = [GBCommentParagraph paragraph];
[para registerItem:[GBParagraphTextItem paragraphItemWithStringValue:example]];
[item registerParagraph:para];

// Register special item to paragraph.
[paragraph registerItem:item];
}

- (void)registerSpecialFromString:(NSString *)string type:(GBSpecialItemType)type usingRegex:(NSString *)regex toParagraph:(GBCommentParagraph *)paragraph { - (void)registerSpecialFromString:(NSString *)string type:(GBSpecialItemType)type usingRegex:(NSString *)regex toParagraph:(GBCommentParagraph *)paragraph {
// Get the description from the string. If empty, warn and exit. // Get the description from the string. If empty, warn and exit.
NSString *trimmed = [string stringByReplacingOccurrencesOfRegex:self.spaceAndNewLineTrimRegex withString:@""]; NSString *description = [string stringByMatching:regex capture:1];
NSString *description = [trimmed stringByMatching:regex capture:1];
if ([description length] == 0) { if ([description length] == 0) {
GBLogWarn(@"Empty special section of type %ld found!", type); GBLogWarn(@"Empty special section of type %ld found!", type);
return; return;
} }


// Prepare paragraph item and process the text. // Prepare paragraph item and process the text.
GBParagraphSpecialItem *item = [GBParagraphSpecialItem specialItemWithType:type stringValue:trimmed]; GBParagraphSpecialItem *item = [GBParagraphSpecialItem specialItemWithType:type stringValue:string];
GBCommentParagraph *para = [GBCommentParagraph paragraph]; GBCommentParagraph *para = [GBCommentParagraph paragraph];
[self registerTextFromString:description toParagraph:para]; [self registerTextFromString:description toParagraph:para];
[item registerParagraph:para]; [item registerParagraph:para];
Expand Down Expand Up @@ -176,15 +207,17 @@ - (void)registerTextFromString:(NSString *)string toParagraph:(GBCommentParagrap
#pragma mark Helper methods #pragma mark Helper methods


- (NSArray *)componentsSeparatedByEmptyLinesFromString:(NSString *)string { - (NSArray *)componentsSeparatedByEmptyLinesFromString:(NSString *)string {
return [string componentsSeparatedByRegex:@"(?m:^\\s*$)"]; // We need to allow lines with tabs to properly detect empty example lines!
return [string componentsSeparatedByRegex:[NSString stringWithFormat:@"(?m:^[ %@]*$)", self.newLinesRegexSymbols]];
} }


- (NSArray *)componentsSeparatedByNewLinesFromString:(NSString *)string { - (NSArray *)componentsSeparatedByNewLinesFromString:(NSString *)string {
return [string componentsSeparatedByRegex:[NSString stringWithUTF8String:"(?:\\r\n|[\n\\v\\f\\r\302\205\\p{Zl}\\p{Zp}])"]]; return [string componentsSeparatedByRegex:[NSString stringWithFormat:@"(?:%@)", self.newLinesRegexSymbols]];
} }


#pragma mark Properties #pragma mark Properties


@synthesize newLinesRegexSymbols;
@synthesize spaceAndNewLineTrimRegex; @synthesize spaceAndNewLineTrimRegex;
@synthesize settings; @synthesize settings;
@synthesize store; @synthesize store;
Expand Down
19 changes: 19 additions & 0 deletions Model/GBParagraphExampleItem.h
@@ -0,0 +1,19 @@
//
// GBParagraphExampleItem.h
// appledoc
//
// Created by Tomaz Kragelj on 2.9.10.
// Copyright (C) 2010, Gentle Bytes. All rights reserved.
//

#import "GBParagraphItem.h"

/** Handles example sections for paragraphs.
Special items are containers for `GBCommentParagraph` which are formatted differently to catch user's attention. There can be several types of special items, to determine the type, use the value of `specialItemType` property.
*/
@interface GBParagraphExampleItem : NSObject {

}

@end
13 changes: 13 additions & 0 deletions Model/GBParagraphExampleItem.m
@@ -0,0 +1,13 @@
//
// GBParagraphExampleItem.m
// appledoc
//
// Created by Tomaz Kragelj on 2.9.10.
// Copyright (C) 2010, Gentle Bytes. All rights reserved.
//

#import "GBParagraphExampleItem.h"

@implementation GBParagraphExampleItem

@end
2 changes: 2 additions & 0 deletions Model/GBParagraphSpecialItem.h
Expand Up @@ -16,6 +16,8 @@ enum {
GBSpecialItemTypeWarning, GBSpecialItemTypeWarning,
/** The `GBParagraphSpecialItem` represents a bug. */ /** The `GBParagraphSpecialItem` represents a bug. */
GBSpecialItemTypeBug, GBSpecialItemTypeBug,
/** The `GBParagraphSpecialItem` represents an example section. */
GBSpecialItemTypeExample,
}; };
typedef NSUInteger GBSpecialItemType; typedef NSUInteger GBSpecialItemType;


Expand Down

0 comments on commit f54495f

Please sign in to comment.