Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support a block-style assembly made of many child assemblies. #92

Closed
jasperblues opened this issue Nov 7, 2013 · 9 comments
Closed
Milestone

Comments

@jasperblues
Copy link
Member

Typhoon provides a few ways to configure environment dependent components, such as the TyphoonPatcher.

Another common pattern is to group environment dependent components together, so that that a different set is provided for each environment. In the XML-style assembly, you can do this by providing a different file. In the block-style assembly, you can provide a category, however this will only work in logic-style tests.

In application-style tests both the production and test version would be loaded, leading to undefined behavior.

Therefore, support an Assembly made up of many children.

@ratkins
Copy link

ratkins commented Nov 7, 2013

+1

@jasperblues
Copy link
Member Author

This is top priority, as the impact is high.

@jasperblues
Copy link
Member Author

Fixed in 1.3.6, whch can be installed via CocoaPods

@jasperblues
Copy link
Member Author

Oops. Stop the press! This solution won't allow sibling assemblies to see each other. . I'll have a solution for that in ~ 2 hours.

@jasperblues jasperblues reopened this Nov 8, 2013
@jasperblues
Copy link
Member Author

OK! Block-style assembly now supports using collaborators from another assembly's interface, where that concrete version of that assembly is not known until run-time.

Here's how:

@interface ExtendedMiddleAgesAssembly : TyphoonAssembly

/**
* id<QuestLocator> is actually the middle-ages assembly, but this shows we can extract a protocol, to 
* just expose the stuff we want to export. 
*/
@property (nonatomic, strong, readwrite) id<QuestLocator> questLocator;

- (id)knightWithExternalQuest;

@end
@implementation ExtendedMiddleAgesAssembly

+ (instancetype)assembly
{
    ExtendedMiddleAgesAssembly* assembly = [super assembly];
   //We're having the proxy stand-in for the interface that won't be bound until run-time. 
    [assembly setQuestLocator:[TyphoonCollaboratingAssemblyProxy proxy]];
    return assembly;
}

- (id)knightWithExternalQuest
{
    return [TyphoonDefinition withClass:[Knight class] properties:^(TyphoonDefinition* definition)
    {
        [definition injectProperty:@selector(quest) withDefinition:[_questLocator environmentDependentQuest]];
    }];
}


@end
- (void)test_allows_initialization_with_a_collection_of_assemblies
{
    TyphoonComponentFactory* factory = [[TyphoonBlockComponentFactory alloc] initWithAssemblies:@[
        [MiddleAgesAssembly assembly],
        [ExtendedMiddleAgesAssembly assembly]
    ]];

    Knight* knight = [(ExtendedMiddleAgesAssembly*) factory knightWithExternalQuest];
    LogDebug(@"Knight: %@", knight);
    assertThat(knight, notNilValue());
}

Now, here's the thing:

Instead of overriding assembly to provide the proxy, I want to have it meta-data driven. But here's the options:

  • Typhoon will see you have a property that extends TyphoonAssembly, and will always proxy it as a collaborator. We could possibly opt-out in future.
  • We provide an "annotation" (ie macro) to say which properties are going to be collaborators. Example: typhoon_provided_at_runtime(@selector(questLocator), @selector(somethingElse))
  • We provide an macro that creates the property, and registers it as an external assembly in one go. Eg typhoon_external_assembly id questLocator . . (I think you can do this with a Macro).

@ratkins, @rhgills , @cesteban, @eriksundin - which of the above options do you like. . . I'm inclinded to option 1 - Typhoon will always treat any property as an external collaborator that will be provided at runtime.

@jasperblues
Copy link
Member Author

I'm starting to favor the explicit "annotation" now:

Examples:

typhoon_provided_at_runtime(questLocator)
typhoon_provided_at_runtime(questLocator, infrasctureComponents)

I would like to finish off this feature in the next day or two. . (Though its already usable in 1.3.7).

@jasperblues
Copy link
Member Author

Instead of macro, I'm now just thinking of an abstract call-back method on TyphoonAssembly:

- (void)resolveCollaboratingAssemblies
{
    [self setQuestProvider:[TyphoonCollaboratingAssemblyProxy proxy]; //Resolved at runtime
    [self setCastles:[CastleAssembly assembly] //Hard-coded
}

@jasperblues
Copy link
Member Author

Done - used the last option. Pushed as 1.3.8

@rhgills
Copy link
Contributor

rhgills commented Nov 9, 2013

Excellent solution; I think it is much better than the other proposed options. Originally I was partial to option 1 (always proxying) but I like the clarity provided by the single line in -[TyphoonAssembly resolveCollaboratingAssemblies].

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants