Skip to content
Browse files

Implemented searching for next comment block within comment source st…

…ring.
  • Loading branch information...
1 parent e12fb72 commit 0e6beb1bfabaa199361a0a16d251ac0979fc52af @tomaz committed Feb 15, 2011
View
5 Processing/GBCommentsProcessor.h
@@ -8,7 +8,6 @@
#import <Foundation/Foundation.h>
-@protocol GBObjectDataProviding;
@class GBComment;
/** Implements comments processing.
@@ -50,12 +49,12 @@
This method processes the given comment's string value and prepares all derives values. It uses the given store for dependent values such as links and similar, so make sure the store has all possible objects already registered. In order to properly handle "local" links, the method also takes `context` parameter which identifies top-level object to which the object which's comment we're processing belongs to. You can pass `nil` however this prevents any local links being processed!
@param comment The comment to process.
- @param context The `GBObjectDataProviding` identifying current context for handling links or `nil`.
+ @param context The object identifying current context for handling links or `nil`.
@param store The store to process against.
@exception NSException Thrown if any of the given parameters is invalid or processing encounters unexpected error.
@see processComment:withStore:
*/
-- (void)processComment:(GBComment *)comment withContext:(id<GBObjectDataProviding>)context store:(id)store;
+- (void)processComment:(GBComment *)comment withContext:(id)context store:(id)store;
/** Processes the given `GBComment` using the given store.
View
49 Processing/GBCommentsProcessor.m
@@ -15,8 +15,8 @@
@interface GBCommentsProcessor ()
- (BOOL)isLineMatchingDirectiveStatement:(NSString *)string;
-- (BOOL)findCommentBlockInLines:(NSArray *)lines blockRange:(NSRange *)range;
-- (void)processCommentBlockInLines:(NSArray *)lines blockRange:(NSRange)range;
+- (BOOL)findCommentBlockInLines:(NSArray *)lines blockRange:(NSRange *)range shortRange:(NSRange *)shortRange;
+- (void)processCommentBlockInLines:(NSArray *)lines blockRange:(NSRange)range shortRange:(NSRange *)shortRange;
@property (retain) id currentContext;
@property (retain) GBComment *currentComment;
@@ -55,7 +55,7 @@ - (void)processComment:(GBComment *)comment withStore:(id)store {
[self processComment:comment withContext:nil store:store];
}
-- (void)processComment:(GBComment *)comment withContext:(id<GBObjectDataProviding>)context store:(id)store {
+- (void)processComment:(GBComment *)comment withContext:(id)context store:(id)store {
NSParameterAssert(comment != nil);
NSParameterAssert(store != nil);
GBLogDebug(@"Processing %@ found in %@...", comment, comment.sourceInfo.filename);
@@ -65,47 +65,48 @@ - (void)processComment:(GBComment *)comment withContext:(id<GBObjectDataProvidin
NSArray *lines = [comment.stringValue arrayOfLines];
NSUInteger line = comment.sourceInfo.lineNumber;
NSRange range = NSMakeRange(0, 0);
+ NSRange shortRange = NSMakeRange(0, 0);
GBLogDebug(@"- Comment has %lu lines.", [lines count]);
- while ([self findCommentBlockInLines:lines blockRange:&range]) {
+ while ([self findCommentBlockInLines:lines blockRange:&range shortRange:&shortRange]) {
GBLogDebug(@"- Found comment block in lines %lu..%lu...", line + range.location, line + range.location + range.length);
[self processCommentBlockInLines:lines blockRange:range];
range.location += range.length;
}
}
-- (BOOL)findCommentBlockInLines:(NSArray *)lines blockRange:(NSRange *)range {
- // Searches the given array of lines for the index of ending line of the block starting at the given index. Effectively this groups all lines that belong to a single block where block is a paragraph text or one of it's items delimited by empty line. The index returned is the index of the last line of the block, so may be the same as the start index, the method takes care to skip empty starting lines if needed and updates start index to point to first block line (but properly detects empty lines belonging to example block). Note that the code is straightforward except for the fact that we need to handle example blocks properly (i.e. can't just trim all whitespace of a line to determine if it's empty or not, instead we need to validate the line is not part of example block).
- NSParameterAssert(range != NULL);
+- (BOOL)findCommentBlockInLines:(NSArray *)lines blockRange:(NSRange *)blockRange shortRange:(NSRange *)shortRange {
+ // Searches the given array of lines starting at line index from the given range until first @ directive is found. Returns YES if block was found, NO otherwise. If block was found, the given range contains the block range of the block within the given array and short range contains the range of first part up to the first empty line.
+ NSParameterAssert(blockRange != NULL);
+ NSParameterAssert(shortRange != NULL);
// First skip all starting empty lines.
- NSUInteger start = range->location;
+ NSUInteger start = blockRange->location;
while (start < [lines count]) {
NSString *line = [lines objectAtIndex:start];
if ([line length] > 0) break;
start++;
}
- // Find the end of block.
- BOOL matchingDirectivesBlock = YES;
- NSUInteger end = start;
- if (start < [lines count]) {
- while (end < [lines count]) {
- NSString *line = [lines objectAtIndex:end];
- if ([line length] == 0) break;
- BOOL isDirective = [self isLineMatchingDirectiveStatement:line];
- if (isDirective && !matchingDirectivesBlock) break;
- if (!isDirective) matchingDirectivesBlock = NO;
- end++;
- }
+ // Find the end of block, which is at the first @ directive; note that we handle each @ directive separately.
+ NSUInteger blockEnd = start;
+ NSUInteger shortEnd = NSNotFound;
+ while (blockEnd < [lines count]) {
+ NSString *line = [lines objectAtIndex:blockEnd];
+ if (blockEnd > start && [self isLineMatchingDirectiveStatement:line]) break;
+ if ([line length] == 0 && shortEnd == NSNotFound) shortEnd = blockEnd;
+ blockEnd++;
}
+ if (shortEnd == NSNotFound) shortEnd = blockEnd;
// Pass results back to client through parameters.
- range->location = start;
- range->length = end - start;
+ blockRange->location = start;
+ blockRange->length = blockEnd - start;
+ shortRange->location = start;
+ shortRange->length = shortEnd - start;
return (start < [lines count]);
}
-- (void)processCommentBlockInLines:(NSArray *)lines blockRange:(NSRange)range {
+- (void)processCommentBlockInLines:(NSArray *)lines blockRange:(NSRange)blockRange shortRange:(NSRange *)shortRange {
// // The given range is guaranteed to point to actual block within the lines array, so we only need to determine the kind of block and how to handle it.
// NSArray *block = [lines subarrayWithRange:range];
// self.currentStartLine = self.currentComment.sourceInfo.lineNumber + range.location;
@@ -123,6 +124,8 @@ - (void)processCommentBlockInLines:(NSArray *)lines blockRange:(NSRange)range {
}
- (BOOL)isLineMatchingDirectiveStatement:(NSString *)string {
+ if ([string isMatchedByRegex:self.components.warningSectionRegex]) return YES;
+ if ([string isMatchedByRegex:self.components.bugSectionRegex]) return YES;
if ([string isMatchedByRegex:self.components.parameterDescriptionRegex]) return YES;
if ([string isMatchedByRegex:self.components.exceptionDescriptionRegex]) return YES;
if ([string isMatchedByRegex:self.components.returnDescriptionRegex]) return YES;
View
2 Testing/GBCommentComponentsListTesting.m
@@ -2,7 +2,7 @@
// GBCommentComponentsListTesting.m
// appledoc
//
-// Created by Tomaz Kragelj on 14.2.10.
+// Created by Tomaz Kragelj on 14.2.11.
// Copyright (C) 2011 Gentle Bytes. All rights reserved.
//
View
114 Testing/GBCommentsProcessorTesting.m
@@ -0,0 +1,114 @@
+//
+// GBCommentsProcessorTesting.m
+// appledoc
+//
+// Created by Tomaz Kragelj on 14.2.11.
+// Copyright (C) 2011 Gentle Bytes. All rights reserved.
+//
+
+#import "GBApplicationSettingsProvider.h"
+#import "GBDataObjects.h"
+#import "GBStore.h"
+#import "GBCommentsProcessor.h"
+
+@interface GBCommentsProcessor (PrivateAPI)
+- (BOOL)findCommentBlockInLines:(NSArray *)lines blockRange:(NSRange *)range shortRange:(NSRange *)shortRange;
+@end
+
+#pragma mark -
+
+@interface GBCommentsProcessorTesting : GBObjectsAssertor
+
+- (OCMockObject *)settingsProviderRepeatFirst:(BOOL)repeat;
+- (void)assertFindCommentWithString:(NSString *)string matchesBlockRange:(NSRange)b shortRange:(NSRange)s;
+
+@end
+
+#pragma mark -
+
+@implementation GBCommentsProcessorTesting
+
+#pragma mark Descriptions testing
+
+//- (void)testProcessCommentWithContextStore_description_shouldRegisterSingleComponent {
+// // setup
+// GBStore *store = [GBTestObjectsRegistry store];
+// GBCommentsProcessor *processor1 = [GBCommentsProcessor processorWithSettingsProvider:[self settingsProviderRepeatFirst:YES]];
+// GBCommentsProcessor *processor2 = [GBCommentsProcessor processorWithSettingsProvider:[self settingsProviderRepeatFirst:NO]];
+// GBComment *comment1 = [GBComment commentWithStringValue:@"Some text\n\nAnother paragraph"];
+// GBComment *comment2 = [GBComment commentWithStringValue:@"Some text\n\nAnother paragraph"];
+// // execute
+// [processor1 processComment:comment1 withContext:nil store:store];
+// [processor2 processComment:comment2 withContext:nil store:store];
+// // verify
+// [self assertComment:comment1 matchesShortDesc:@"Some text" longDesc:@"Some text\n\nAnother paragraph", nil];
+// [self assertComment:comment2 matchesShortDesc:@"Some text" longDesc:@"Another paragraph", nil];
+//}
+
+#pragma mark Private methods testing
+
+- (void)testFindCommentBlockInLinesBlockRangeShortRange_shouldDetectSingleComponent {
+ [self assertFindCommentWithString:@"line" matchesBlockRange:NSMakeRange(0, 1) shortRange:NSMakeRange(0, 1)];
+ [self assertFindCommentWithString:@"line1\nline2" matchesBlockRange:NSMakeRange(0, 2) shortRange:NSMakeRange(0, 2)];
+ [self assertFindCommentWithString:@"para1\n\npara" matchesBlockRange:NSMakeRange(0, 3) shortRange:NSMakeRange(0, 1)];
+ [self assertFindCommentWithString:@"para1\n\npara2\n\npara3" matchesBlockRange:NSMakeRange(0, 5) shortRange:NSMakeRange(0, 1)];
+}
+
+- (void)testFindCommentBlockInLinesBlockRangeShortRange_shouldDetectSingleComponentUpToDirective {
+ [self assertFindCommentWithString:@"line\n@warning desc" matchesBlockRange:NSMakeRange(0, 1) shortRange:NSMakeRange(0, 1)];
+ [self assertFindCommentWithString:@"line\n\n@warning desc" matchesBlockRange:NSMakeRange(0, 2) shortRange:NSMakeRange(0, 1)];
+ [self assertFindCommentWithString:@"para1\n\npara2\n@warning desc" matchesBlockRange:NSMakeRange(0, 3) shortRange:NSMakeRange(0, 1)];
+ [self assertFindCommentWithString:@"para1\n\npara2\n\n@warning desc" matchesBlockRange:NSMakeRange(0, 4) shortRange:NSMakeRange(0, 1)];
+}
+
+- (void)testFindCommentBlockInLinesBlockRangeShortRange_shouldDetectDirectiveComponentUpToEndOfLines {
+ [self assertFindCommentWithString:@"@warning desc" matchesBlockRange:NSMakeRange(0, 1) shortRange:NSMakeRange(0, 1)];
+ [self assertFindCommentWithString:@"@warning line1\nline2" matchesBlockRange:NSMakeRange(0, 2) shortRange:NSMakeRange(0, 2)];
+ [self assertFindCommentWithString:@"@warning para1\n\npara2" matchesBlockRange:NSMakeRange(0, 3) shortRange:NSMakeRange(0, 1)];
+}
+
+- (void)testFindCommentBlockInLinesBlockRangeShortRange_shouldDetectDirectiveComponentUpToNextDirective {
+ [self assertFindCommentWithString:@"@warning desc\n@warning next" matchesBlockRange:NSMakeRange(0, 1) shortRange:NSMakeRange(0, 1)];
+ [self assertFindCommentWithString:@"@warning desc\n\n@warning next" matchesBlockRange:NSMakeRange(0, 2) shortRange:NSMakeRange(0, 1)];
+ [self assertFindCommentWithString:@"@warning line1\nline2\n@warning next" matchesBlockRange:NSMakeRange(0, 2) shortRange:NSMakeRange(0, 2)];
+ [self assertFindCommentWithString:@"@warning line1\nline2\n\n@warning next" matchesBlockRange:NSMakeRange(0, 3) shortRange:NSMakeRange(0, 2)];
+ [self assertFindCommentWithString:@"@warning para1\n\npara2\n@warning next" matchesBlockRange:NSMakeRange(0, 3) shortRange:NSMakeRange(0, 1)];
+ [self assertFindCommentWithString:@"@warning para1\n\npara2\n\n@warning next" matchesBlockRange:NSMakeRange(0, 4) shortRange:NSMakeRange(0, 1)];
+}
+
+- (void)testFindCommentBlockInLinesBlockRangeShortRange_shouldStopAtAnyDirective {
+ NSRange blockRange = NSMakeRange(0, 1);
+ NSRange shortRange = NSMakeRange(0, 1);
+ [self assertFindCommentWithString:@"line\n@warning desc" matchesBlockRange:blockRange shortRange:shortRange];
+ [self assertFindCommentWithString:@"line\n@bug desc" matchesBlockRange:blockRange shortRange:shortRange];
+ [self assertFindCommentWithString:@"line\n@param name desc" matchesBlockRange:blockRange shortRange:shortRange];
+ [self assertFindCommentWithString:@"line\n@return desc" matchesBlockRange:blockRange shortRange:shortRange];
+ [self assertFindCommentWithString:@"line\n@returns desc" matchesBlockRange:blockRange shortRange:shortRange];
+ [self assertFindCommentWithString:@"line\n@exception name desc" matchesBlockRange:blockRange shortRange:shortRange];
+ [self assertFindCommentWithString:@"line\n@see desc" matchesBlockRange:blockRange shortRange:shortRange];
+ [self assertFindCommentWithString:@"line\n@sa desc" matchesBlockRange:blockRange shortRange:shortRange];
+}
+
+#pragma Creation & assertion methods
+
+- (OCMockObject *)settingsProviderRepeatFirst:(BOOL)repeat {
+ OCMockObject *result = [GBTestObjectsRegistry mockSettingsProvider];
+ [[[result stub] andReturnValue:[NSNumber numberWithBool:repeat]] repeatFirstParagraphForMemberDescription];
+ return result;
+}
+
+- (void)assertFindCommentWithString:(NSString *)string matchesBlockRange:(NSRange)b shortRange:(NSRange)s {
+ // setup
+ GBCommentsProcessor *processor = [GBCommentsProcessor processorWithSettingsProvider:[GBTestObjectsRegistry realSettingsProvider]];
+ // execute
+ NSRange blockRange = NSMakeRange(0, 0);
+ NSRange shortRange = NSMakeRange(0, 0);
+ [processor findCommentBlockInLines:[string arrayOfLines] blockRange:&blockRange shortRange:&shortRange];
+ // verify
+ assertThatInteger(blockRange.location, equalToInteger(b.location));
+ assertThatInteger(blockRange.length, equalToInteger(b.length));
+ assertThatInteger(shortRange.location, equalToInteger(s.location));
+ assertThatInteger(shortRange.length, equalToInteger(s.length));
+}
+
+@end
View
6 Testing/GBObjectsAssertor.h
@@ -19,10 +19,14 @@
@interface GBObjectsAssertor : GHTestCase
- (void)assertIvar:(GBIvarData *)ivar matches:(NSString *)firstType,... NS_REQUIRES_NIL_TERMINATION;
+- (void)assertMethod:(GBMethodData *)method matchesType:(GBMethodType)type start:(NSString *)first components:(va_list)args;
- (void)assertMethod:(GBMethodData *)method matchesInstanceComponents:(NSString *)firstItem,... NS_REQUIRES_NIL_TERMINATION;
- (void)assertMethod:(GBMethodData *)method matchesClassComponents:(NSString *)firstItem,... NS_REQUIRES_NIL_TERMINATION;
- (void)assertMethod:(GBMethodData *)method matchesPropertyComponents:(NSString *)firstItem,... NS_REQUIRES_NIL_TERMINATION;
-- (void)assertMethod:(GBMethodData *)method matchesType:(GBMethodType)type start:(NSString *)first components:(va_list)args;
- (void)assertFormattedComponents:(NSArray *)components match:(NSString *)first,... NS_REQUIRES_NIL_TERMINATION;
+- (void)assertCommentComponents:(GBCommentComponentsList *)components matchesValues:(NSString *)first values:(va_list)args;
+- (void)assertCommentComponents:(GBCommentComponentsList *)components matchesStringValues:(NSString *)first, ... NS_REQUIRES_NIL_TERMINATION;
+- (void)assertComment:(GBComment *)comment matchesShortDesc:(NSString *)shortValue longDesc:(NSString *)first, ... NS_REQUIRES_NIL_TERMINATION;
+
@end
View
31 Testing/GBObjectsAssertor.m
@@ -139,4 +139,35 @@ - (void)assertFormattedComponents:(NSArray *)components match:(NSString *)first,
}
}
+#pragma mark Comment creation and assertion methods
+
+- (void)assertCommentComponents:(GBCommentComponentsList *)components matchesValues:(NSString *)first values:(va_list)args {
+ NSMutableArray *expected = [NSMutableArray arrayWithObject:first];
+ NSString *value;
+ while ((value = va_arg(args, NSString *))) {
+ [expected addObject:value];
+ }
+ assertThatInteger([components.components count], equalToInteger([expected count]));
+ for (NSUInteger i=0; i<[components.components count]; i++) {
+ NSString *expectedValue = [expected objectAtIndex:i];
+ NSString *actualValue = [[components.components objectAtIndex:i] stringValue];
+ assertThat(actualValue, is(expectedValue));
+ }
+}
+
+- (void)assertCommentComponents:(GBCommentComponentsList *)components matchesStringValues:(NSString *)first, ... {
+ va_list args;
+ va_start(args, first);
+ [self assertCommentComponents:components matchesValues:first values:args];
+ va_end(args);
+}
+
+- (void)assertComment:(GBComment *)comment matchesShortDesc:(NSString *)shortValue longDesc:(NSString *)first, ... {
+ assertThat(comment.shortDescription, is(shortValue));
+ va_list args;
+ va_start(args, first);
+ [self assertCommentComponents:comment.longDescription matchesValues:first values:args];
+ va_end(args);
+}
+
@end
View
4 appledoc.xcodeproj/project.pbxproj
@@ -159,6 +159,7 @@
73AF4ECC130938F3001152DB /* GBCommentComponentsList.m in Sources */ = {isa = PBXBuildFile; fileRef = 73AF4ECB130938F3001152DB /* GBCommentComponentsList.m */; };
73AF4ECD130938F3001152DB /* GBCommentComponentsList.m in Sources */ = {isa = PBXBuildFile; fileRef = 73AF4ECB130938F3001152DB /* GBCommentComponentsList.m */; };
73AF4ECF13093B5A001152DB /* GBCommentComponentsListTesting.m in Sources */ = {isa = PBXBuildFile; fileRef = 73AF4ECE13093B5A001152DB /* GBCommentComponentsListTesting.m */; };
+ 73B99A891309452E00890FA0 /* GBCommentsProcessorTesting.m in Sources */ = {isa = PBXBuildFile; fileRef = 73B99A881309452E00890FA0 /* GBCommentsProcessorTesting.m */; };
73CF8131122D3824005B7E26 /* RegexKitLite.m in Sources */ = {isa = PBXBuildFile; fileRef = 73CF8130122D3824005B7E26 /* RegexKitLite.m */; };
73CF8132122D3824005B7E26 /* RegexKitLite.m in Sources */ = {isa = PBXBuildFile; fileRef = 73CF8130122D3824005B7E26 /* RegexKitLite.m */; };
73D2524612A2ED610024F9F9 /* GBOutputGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 73D2524512A2ED610024F9F9 /* GBOutputGenerator.m */; };
@@ -336,6 +337,7 @@
73AF4ECA130938F3001152DB /* GBCommentComponentsList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GBCommentComponentsList.h; sourceTree = "<group>"; };
73AF4ECB130938F3001152DB /* GBCommentComponentsList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GBCommentComponentsList.m; sourceTree = "<group>"; };
73AF4ECE13093B5A001152DB /* GBCommentComponentsListTesting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GBCommentComponentsListTesting.m; sourceTree = "<group>"; };
+ 73B99A881309452E00890FA0 /* GBCommentsProcessorTesting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GBCommentsProcessorTesting.m; sourceTree = "<group>"; };
73CF8130122D3824005B7E26 /* RegexKitLite.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RegexKitLite.m; sourceTree = "<group>"; };
73D2524312A2EA340024F9F9 /* html */ = {isa = PBXFileReference; lastKnownFileType = folder; path = html; sourceTree = "<group>"; };
73D2524412A2ED610024F9F9 /* GBOutputGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GBOutputGenerator.h; sourceTree = "<group>"; };
@@ -888,6 +890,7 @@
739C0C4612AC258B00F0130B /* GBProcessor-UndocumentedObjectsTesting.m */,
739C0C4812AC284E00F0130B /* GBProcessor-CategoriesMergingTesting.m */,
7374D91412AE3A9C003CB492 /* GBProcessor-MemberDocCopyingTesting.m */,
+ 73B99A881309452E00890FA0 /* GBCommentsProcessorTesting.m */,
);
name = Processing;
sourceTree = "<group>";
@@ -1207,6 +1210,7 @@
73AF4EC913093570001152DB /* GBCommentComponent.m in Sources */,
73AF4ECD130938F3001152DB /* GBCommentComponentsList.m in Sources */,
73AF4ECF13093B5A001152DB /* GBCommentComponentsListTesting.m in Sources */,
+ 73B99A891309452E00890FA0 /* GBCommentsProcessorTesting.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

0 comments on commit 0e6beb1

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