From a0ed655705f6ac230d8cbf57627586c8577dc4a2 Mon Sep 17 00:00:00 2001 From: Tomaz Kragelj Date: Tue, 1 Mar 2011 13:53:32 +0100 Subject: [PATCH] Fixed methods and sections merging for GBMethodsProvider. Closes #73. The problem was in merging code always creating section for each merged method if not found in the original. This lead to creation of "Other methods" section when merging implementation into definition. This situation is properly handled now by only creating sections for methods not found in the original. --- Model/GBMethodsProvider.m | 29 +++++++++++++++-------- Testing/GBMethodsProviderTesting.m | 37 ++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/Model/GBMethodsProvider.m b/Model/GBMethodsProvider.m index d8ba5dc1..5fa3ef79 100644 --- a/Model/GBMethodsProvider.m +++ b/Model/GBMethodsProvider.m @@ -158,19 +158,30 @@ - (void)mergeDataFromMethodsProvider:(GBMethodsProvider *)source { // If a method with the same selector is found while merging from source, we should check if the type also matches. If so, we can merge the data from the source's method. However if the type doesn't match, we should ignore the method alltogether (ussually this is due to custom property implementation). We should probably deal with this scenario more inteligently, but it seems it works... if (!source || source == self) return; GBLogDebug(@"%@: Merging methods from %@...", _parent, source->_parent); + + // First merge all existing methods regardless of section and prepare the list of all new methods. + NSMutableArray *newMethods = [NSMutableArray array]; + [source.methods enumerateObjectsUsingBlock:^(GBMethodData *sourceMethod, NSUInteger idx, BOOL *stop) { + GBMethodData *existingMethod = [self methodBySelector:sourceMethod.methodSelector]; + if (!existingMethod) { + [newMethods addObject:sourceMethod]; + return; + } + [existingMethod mergeDataFromObject:sourceMethod]; + }]; + if ([newMethods count] == 0) return; + + // Second merge all sections; only use sections for methods that were not registered yet! Note that we need to remember current section so that we restore it later on. GBMethodSectionData *previousSection = _registeringSection; [source.sections enumerateObjectsUsingBlock:^(GBMethodSectionData *sourceSection, NSUInteger idx, BOOL *stop) { - GBMethodSectionData *existingSection = [_sectionsByNames objectForKey:sourceSection.sectionName]; - if (!existingSection) existingSection = [self registerSectionWithName:sourceSection.sectionName]; - _registeringSection = existingSection; - - [sourceSection.methods enumerateObjectsUsingBlock:^(GBMethodData *sourceMethod, NSUInteger idx, BOOL *stop) { - GBMethodData *existingMethod = [_methodsBySelectors objectForKey:sourceMethod.methodSelector]; - if (existingMethod) { - if (existingMethod.methodType == sourceMethod.methodType) [existingMethod mergeDataFromObject:sourceMethod]; + [newMethods enumerateObjectsUsingBlock:^(GBMethodData *sourceMethod, NSUInteger idx, BOOL *stop) { + if ([sourceSection.methods containsObject:sourceMethod]) { + GBMethodSectionData *existingSection = [_sectionsByNames objectForKey:sourceSection.sectionName]; + if (!existingSection) existingSection = [self registerSectionWithName:sourceSection.sectionName]; + _registeringSection = existingSection; + [self registerMethod:sourceMethod]; return; } - [self registerMethod:sourceMethod]; }]; }]; _registeringSection = previousSection; diff --git a/Testing/GBMethodsProviderTesting.m b/Testing/GBMethodsProviderTesting.m index 55b41d79..0e176e26 100644 --- a/Testing/GBMethodsProviderTesting.m +++ b/Testing/GBMethodsProviderTesting.m @@ -439,6 +439,43 @@ - (void)testMergeDataFromObjectsProvider_shouldPreserveCurrentSectionForNewMetho assertThat([[section.methods objectAtIndex:0] methodSelector], is(@"m2:")); } +- (void)testMergeDataFromObjectsProvider_shouldUseOriginalSectionForExistingMethodsEvenIfFoundInDifferentSection { + // setup + GBMethodsProvider *original = [[GBMethodsProvider alloc] initWithParentObject:self]; + [original registerSectionWithName:@"Section1"]; + [original registerMethod:[GBTestObjectsRegistry instanceMethodWithNames:@"m1", nil]]; + GBMethodsProvider *source = [[GBMethodsProvider alloc] initWithParentObject:self]; + [source registerSectionWithName:@"Section2"]; + [source registerMethod:[GBTestObjectsRegistry instanceMethodWithNames:@"m1", nil]]; + // execute + [original mergeDataFromMethodsProvider:source]; + // verify + NSArray *sections = [original sections]; + assertThatInteger([sections count], equalToInteger(1)); + GBMethodSectionData *section = [sections objectAtIndex:0]; + assertThat([section sectionName], is(@"Section1")); + assertThatInteger([section.methods count], equalToInteger(1)); + assertThat([[section.methods objectAtIndex:0] methodSelector], is(@"m1:")); +} + +- (void)testMergeDataFromObjectsProvider_shouldUseOriginalSectionForExistingMethodsFromDefaultSection { + // setup + GBMethodsProvider *original = [[GBMethodsProvider alloc] initWithParentObject:self]; + [original registerSectionWithName:@"Section1"]; + [original registerMethod:[GBTestObjectsRegistry instanceMethodWithNames:@"m1", nil]]; + GBMethodsProvider *source = [[GBMethodsProvider alloc] initWithParentObject:self]; + [source registerMethod:[GBTestObjectsRegistry instanceMethodWithNames:@"m1", nil]]; + // execute + [original mergeDataFromMethodsProvider:source]; + // verify + NSArray *sections = [original sections]; + assertThatInteger([sections count], equalToInteger(1)); + GBMethodSectionData *section = [sections objectAtIndex:0]; + assertThat([section sectionName], is(@"Section1")); + assertThatInteger([section.methods count], equalToInteger(1)); + assertThat([[section.methods objectAtIndex:0] methodSelector], is(@"m1:")); +} + #pragma mark Unregistering handling - (void)testUnregisterMethod_shouldRemoveMethodFromMethods {