Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

KISS

  • Loading branch information...
commit 6c6ce27daff83c8e16b014bc471c657cbd2492a8 1 parent 26f510c
@groue authored
View
238 src/classes/GRMustacheRuntime.m
@@ -43,11 +43,7 @@
@interface GRMustacheRuntime()
+ (BOOL)objectIsFoundationCollectionWhoseImplementationOfValueForKeyReturnsAnotherCollection:(id)object;
-- (id)initWithTemplate:(GRMustacheTemplate *)template contextObject:(id)contextObject;
-- (id)initWithTemplate:(GRMustacheTemplate *)template parent:(GRMustacheRuntime *)parent parentHasContext:(BOOL)parentHasContext parentHasFilter:(BOOL)parentHasFilter parentHasTemplateDelegate:(BOOL)parentHasTemplateDelegate parentHasTemplateOverride:(BOOL)parentHasTemplateOverride templateDelegate:(id<GRMustacheTemplateDelegate>)templateDelegate;
-- (id)initWithTemplate:(GRMustacheTemplate *)template parent:(GRMustacheRuntime *)parent parentHasContext:(BOOL)parentHasContext parentHasFilter:(BOOL)parentHasFilter parentHasTemplateDelegate:(BOOL)parentHasTemplateDelegate parentHasTemplateOverride:(BOOL)parentHasTemplateOverride contextObject:(id)contextObject;
-- (id)initWithTemplate:(GRMustacheTemplate *)template parent:(GRMustacheRuntime *)parent parentHasContext:(BOOL)parentHasContext parentHasFilter:(BOOL)parentHasFilter parentHasTemplateDelegate:(BOOL)parentHasTemplateDelegate parentHasTemplateOverride:(BOOL)parentHasTemplateOverride filterObject:(id)filterObject;
-- (id)initWithTemplate:(GRMustacheTemplate *)template parent:(GRMustacheRuntime *)parent parentHasContext:(BOOL)parentHasContext parentHasFilter:(BOOL)parentHasFilter parentHasTemplateDelegate:(BOOL)parentHasTemplateDelegate parentHasTemplateOverride:(BOOL)parentHasTemplateOverride templateOverride:(GRMustacheTemplateOverride *)templateOverride;
+- (id)initWithTemplate:(GRMustacheTemplate *)template contextStack:(NSArray *)contextStack filterStack:(NSArray *)filterStack delegateStack:(NSArray *)delegateStack templateOverrideStack:(NSArray *)templateOverrideStack;
- (void)assertAcyclicTemplateOverride:(GRMustacheTemplateOverride *)templateOverride;
@end
@@ -60,21 +56,14 @@ + (void)preventNSUndefinedKeyExceptionAttack
+ (id)runtime
{
- return [[[self alloc] initWithTemplate:nil contextObject:nil] autorelease];
+ return [self runtimeWithTemplate:nil contextStack:nil];
}
-+ (id)runtimeWithTemplate:(GRMustacheTemplate *)template contextObject:(id)contextObject
++ (id)runtimeWithTemplate:(GRMustacheTemplate *)template contextStack:(NSArray *)contextStack
{
- return [[[self alloc] initWithTemplate:template contextObject:contextObject] autorelease];
-}
-
-+ (id)runtimeWithTemplate:(GRMustacheTemplate *)template contextObjects:(NSArray *)contextObjects
-{
- GRMustacheRuntime *runtime = [[[self alloc] initWithTemplate:template contextObject:nil] autorelease];
- for (id contextObject in contextObjects) {
- runtime = [runtime runtimeByAddingContextObject:contextObject];
- }
- return runtime;
+ NSArray *delegateStack = template.delegate ? [NSArray arrayWithObject:template.delegate] : nil;
+ NSArray *filterStack = [NSArray arrayWithObject:[GRMustacheFilterLibrary filterLibrary]];
+ return [[[self alloc] initWithTemplate:template contextStack:contextStack filterStack:filterStack delegateStack:delegateStack templateOverrideStack:nil] autorelease];
}
- (GRMustacheRuntime *)runtimeByAddingTemplateDelegate:(id<GRMustacheTemplateDelegate>)templateDelegate
@@ -83,13 +72,11 @@ - (GRMustacheRuntime *)runtimeByAddingTemplateDelegate:(id<GRMustacheTemplateDel
return self;
}
- return [[[GRMustacheRuntime alloc] initWithTemplate:_template
- parent:self
- parentHasContext:_contextObject || _parentHasContext
- parentHasFilter:_filterObject || _parentHasFilter
- parentHasTemplateDelegate:_templateDelegate || _parentHasTemplateDelegate
- parentHasTemplateOverride:_templateOverride || _parentHasTemplateOverride
- templateDelegate:templateDelegate] autorelease];
+ // top of the stack is first object
+ NSArray *delegateStack = [NSArray arrayWithObject:templateDelegate];
+ if (_delegateStack) { delegateStack = [delegateStack arrayByAddingObjectsFromArray:_delegateStack]; }
+
+ return [[[GRMustacheRuntime alloc] initWithTemplate:_template contextStack:_contextStack filterStack:_filterStack delegateStack:delegateStack templateOverrideStack:_templateOverrideStack] autorelease];
}
- (GRMustacheRuntime *)runtimeByAddingContextObject:(id)contextObject
@@ -98,13 +85,11 @@ - (GRMustacheRuntime *)runtimeByAddingContextObject:(id)contextObject
return self;
}
- return [[[GRMustacheRuntime alloc] initWithTemplate:_template
- parent:self
- parentHasContext:_contextObject || _parentHasContext
- parentHasFilter:_filterObject || _parentHasFilter
- parentHasTemplateDelegate:_templateDelegate || _parentHasTemplateDelegate
- parentHasTemplateOverride:_templateOverride || _parentHasTemplateOverride
- contextObject:contextObject] autorelease];
+ // top of the stack is first object
+ NSArray *contextStack = [NSArray arrayWithObject:contextObject];
+ if (_contextStack) { contextStack = [contextStack arrayByAddingObjectsFromArray:_contextStack]; }
+
+ return [[[GRMustacheRuntime alloc] initWithTemplate:_template contextStack:contextStack filterStack:_filterStack delegateStack:_delegateStack templateOverrideStack:_templateOverrideStack] autorelease];
}
- (GRMustacheRuntime *)runtimeByAddingFilterObject:(id)filterObject;
@@ -113,13 +98,11 @@ - (GRMustacheRuntime *)runtimeByAddingFilterObject:(id)filterObject;
return self;
}
- return [[[GRMustacheRuntime alloc] initWithTemplate:_template
- parent:self
- parentHasContext:_contextObject || _parentHasContext
- parentHasFilter:_filterObject || _parentHasFilter
- parentHasTemplateDelegate:_templateDelegate || _parentHasTemplateDelegate
- parentHasTemplateOverride:_templateOverride || _parentHasTemplateOverride
- filterObject:filterObject] autorelease];
+ // top of the stack is first object
+ NSArray *filterStack = [NSArray arrayWithObject:filterObject];
+ if (_filterStack) { filterStack = [filterStack arrayByAddingObjectsFromArray:_filterStack]; }
+
+ return [[[GRMustacheRuntime alloc] initWithTemplate:_template contextStack:_contextStack filterStack:filterStack delegateStack:_delegateStack templateOverrideStack:_templateOverrideStack] autorelease];
}
- (GRMustacheRuntime *)runtimeByAddingTemplateOverride:(GRMustacheTemplateOverride *)templateOverride
@@ -130,115 +113,97 @@ - (GRMustacheRuntime *)runtimeByAddingTemplateOverride:(GRMustacheTemplateOverri
[self assertAcyclicTemplateOverride:templateOverride];
- return [[[GRMustacheRuntime alloc] initWithTemplate:_template
- parent:self
- parentHasContext:_contextObject || _parentHasContext
- parentHasFilter:_filterObject || _parentHasFilter
- parentHasTemplateDelegate:_templateDelegate || _parentHasTemplateDelegate
- parentHasTemplateOverride:_templateOverride || _parentHasTemplateOverride
- templateOverride:templateOverride] autorelease];
+ // top of the stack is first object
+ NSArray *templateOverrideStack = [NSArray arrayWithObject:templateOverride];
+ if (_templateOverrideStack) { templateOverrideStack = [templateOverrideStack arrayByAddingObjectsFromArray:_templateOverrideStack]; }
+
+ return [[[GRMustacheRuntime alloc] initWithTemplate:_template contextStack:_contextStack filterStack:_filterStack delegateStack:_delegateStack templateOverrideStack:templateOverrideStack] autorelease];
}
- (void)dealloc
{
- [_parent release];
[_template release];
- [_templateDelegate release];
- [_contextObject release];
- [_filterObject release];
- [_templateOverride release];
+ [_contextStack release];
+ [_filterStack release];
+ [_delegateStack release];
+ [_templateOverrideStack release];
[super dealloc];
}
- (id)currentContextValue
{
- if (_contextObject) {
- return [[_contextObject retain] autorelease];
- }
- if (_parentHasContext) {
- return [_parent currentContextValue];
- }
- return nil;
+ // top of the stack is first object
+ return [_contextStack objectAtIndex:0];
}
- (id)contextValueForKey:(NSString *)key
{
- if (_contextObject) {
- id value = [GRMustacheRuntime valueForKey:key inObject:_contextObject];
+ // top of the stack is first object
+ for (id contextObject in _contextStack) {
+ id value = [GRMustacheRuntime valueForKey:key inObject:contextObject];
if (value != nil) { return value; }
}
- if (_parentHasContext) {
- return [_parent contextValueForKey:key];
- }
return nil;
}
- (id)filterValueForKey:(NSString *)key
{
- if (_filterObject) {
- id value = [GRMustacheRuntime valueForKey:key inObject:_filterObject];
+ // top of the stack is first object
+ for (id filterObject in _filterStack) {
+ id value = [GRMustacheRuntime valueForKey:key inObject:filterObject];
if (value != nil) { return value; }
}
- if (_parentHasFilter) {
- return [_parent filterValueForKey:key];
- }
return nil;
}
- (void)delegateValue:(id)value interpretation:(GRMustacheInterpretation)interpretation forRenderingToken:(GRMustacheToken *)token usingBlock:(void(^)(id value))block
{
- if (_templateDelegate) {
- NSAssert(_template, @"WTF");
-
- GRMustacheInvocation *invocation = [[[GRMustacheInvocation alloc] init] autorelease];
- invocation.token = token;
- invocation.returnValue = value;
-
- if ([_templateDelegate respondsToSelector:@selector(template:willInterpretReturnValueOfInvocation:as:)]) {
- [_templateDelegate template:_template willInterpretReturnValueOfInvocation:invocation as:interpretation];
- }
-
- if (_parent) {
- [_parent delegateValue:invocation.returnValue interpretation:interpretation forRenderingToken:token usingBlock:block];
- } else {
- block(invocation.returnValue);
- }
-
- if ([_templateDelegate respondsToSelector:@selector(template:didInterpretReturnValueOfInvocation:as:)]) {
- [_templateDelegate template:_template didInterpretReturnValueOfInvocation:invocation as:interpretation];
+ NSAssert(_template, @"WTF");
+
+ // fast path
+ if (_delegateStack == nil) {
+ block(value);
+ return;
+ }
+
+ GRMustacheInvocation *invocation = [[[GRMustacheInvocation alloc] init] autorelease];
+ invocation.token = token;
+ invocation.returnValue = value;
+
+ // top of the stack is first object
+ for (id<GRMustacheTemplateDelegate> delegate in _delegateStack) {
+ if ([delegate respondsToSelector:@selector(template:willInterpretReturnValueOfInvocation:as:)]) {
+ [delegate template:_template willInterpretReturnValueOfInvocation:invocation as:interpretation];
}
- } else {
- if (_parentHasTemplateDelegate) {
- [_parent delegateValue:value interpretation:interpretation forRenderingToken:token usingBlock:block];
- } else {
- block(value);
+ }
+
+ block(invocation.returnValue);
+
+ for (id<GRMustacheTemplateDelegate> delegate in [_delegateStack reverseObjectEnumerator]) {
+ if ([delegate respondsToSelector:@selector(template:didInterpretReturnValueOfInvocation:as:)]) {
+ [delegate template:_template didInterpretReturnValueOfInvocation:invocation as:interpretation];
}
}
}
- (id<GRMustacheRenderingElement>)resolveRenderingElement:(id<GRMustacheRenderingElement>)element
{
- if (_templateOverride) {
- element = [_templateOverride resolveRenderingElement:element];
- }
- if (_parentHasTemplateOverride) {
- element = [_parent resolveRenderingElement:element];
+ // top of the stack is first object
+ for (GRMustacheTemplateOverride *templateOverride in _templateOverrideStack) {
+ element = [templateOverride resolveRenderingElement:element];
}
return element;
}
#pragma mark - Private
-- (void)assertAcyclicTemplateOverride:(GRMustacheTemplateOverride *)templateOverride
+- (void)assertAcyclicTemplateOverride:(GRMustacheTemplateOverride *)otherTemplateOverride
{
- if (_templateOverride) {
- if (_templateOverride.template == templateOverride.template) {
+ for (GRMustacheTemplateOverride *templateOverride in _templateOverrideStack) {
+ if (templateOverride.template == otherTemplateOverride.template) {
[NSException raise:GRMustacheRenderingException format:@"Override cycle"];
}
}
- if (_parentHasTemplateOverride) {
- [_parent assertAcyclicTemplateOverride:templateOverride];
- }
}
+ (id)valueForKey:(NSString *)key inObject:(id)object
@@ -286,74 +251,15 @@ + (id)valueForKey:(NSString *)key inObject:(id)object
return value;
}
-- (id)initWithTemplate:(GRMustacheTemplate *)template contextObject:(id)contextObject
-{
- self = [super init];
- if (self) {
- _template = [template retain];
- _templateDelegate = [template.delegate retain];
- _filterObject = [[GRMustacheFilterLibrary filterLibrary] retain];
- _contextObject = [contextObject retain];
- }
- return self;
-}
-
-- (id)initWithTemplate:(GRMustacheTemplate *)template parent:(GRMustacheRuntime *)parent parentHasContext:(BOOL)parentHasContext parentHasFilter:(BOOL)parentHasFilter parentHasTemplateDelegate:(BOOL)parentHasTemplateDelegate parentHasTemplateOverride:(BOOL)parentHasTemplateOverride templateDelegate:(id<GRMustacheTemplateDelegate>)templateDelegate
-{
- self = [super init];
- if (self) {
- _template = [template retain];
- _parent = [parent retain];
- _templateDelegate = [templateDelegate retain];
- _parentHasContext = parentHasContext;
- _parentHasFilter = parentHasFilter;
- _parentHasTemplateDelegate = parentHasTemplateDelegate;
- _parentHasTemplateOverride = parentHasTemplateOverride;
- }
- return self;
-}
-
-- (id)initWithTemplate:(GRMustacheTemplate *)template parent:(GRMustacheRuntime *)parent parentHasContext:(BOOL)parentHasContext parentHasFilter:(BOOL)parentHasFilter parentHasTemplateDelegate:(BOOL)parentHasTemplateDelegate parentHasTemplateOverride:(BOOL)parentHasTemplateOverride contextObject:(id)contextObject
-{
- self = [super init];
- if (self) {
- _template = [template retain];
- _parent = [parent retain];
- _contextObject = [contextObject retain];
- _parentHasContext = parentHasContext;
- _parentHasFilter = parentHasFilter;
- _parentHasTemplateDelegate = parentHasTemplateDelegate;
- _parentHasTemplateOverride = parentHasTemplateOverride;
- }
- return self;
-}
-
-- (id)initWithTemplate:(GRMustacheTemplate *)template parent:(GRMustacheRuntime *)parent parentHasContext:(BOOL)parentHasContext parentHasFilter:(BOOL)parentHasFilter parentHasTemplateDelegate:(BOOL)parentHasTemplateDelegate parentHasTemplateOverride:(BOOL)parentHasTemplateOverride filterObject:(id)filterObject
-{
- self = [super init];
- if (self) {
- _template = [template retain];
- _parent = [parent retain];
- _filterObject = [filterObject retain];
- _parentHasContext = parentHasContext;
- _parentHasFilter = parentHasFilter;
- _parentHasTemplateDelegate = parentHasTemplateDelegate;
- _parentHasTemplateOverride = parentHasTemplateOverride;
- }
- return self;
-}
-
-- (id)initWithTemplate:(GRMustacheTemplate *)template parent:(GRMustacheRuntime *)parent parentHasContext:(BOOL)parentHasContext parentHasFilter:(BOOL)parentHasFilter parentHasTemplateDelegate:(BOOL)parentHasTemplateDelegate parentHasTemplateOverride:(BOOL)parentHasTemplateOverride templateOverride:(GRMustacheTemplateOverride *)templateOverride
+- (id)initWithTemplate:(GRMustacheTemplate *)template contextStack:(NSArray *)contextStack filterStack:(NSArray *)filterStack delegateStack:(NSArray *)delegateStack templateOverrideStack:(NSArray *)templateOverrideStack
{
self = [super init];
if (self) {
_template = [template retain];
- _parent = [parent retain];
- _templateOverride = [templateOverride retain];
- _parentHasContext = parentHasContext;
- _parentHasFilter = parentHasFilter;
- _parentHasTemplateDelegate = parentHasTemplateDelegate;
- _parentHasTemplateOverride = parentHasTemplateOverride;
+ _contextStack = [contextStack retain];
+ _filterStack = [filterStack retain];
+ _delegateStack = [delegateStack retain];
+ _templateOverrideStack = [templateOverrideStack retain];
}
return self;
}
View
56 src/classes/GRMustacheRuntime_private.h
@@ -39,11 +39,12 @@ extern BOOL GRMustacheRuntimeDidCatchNSUndefinedKeyException;
/**
* The GRMustacheRuntime responsability is to provide a runtime context for
- * Mustache rendering. It internally maintains three stacks:
+ * Mustache rendering. It internally maintains the following stacks:
*
* - a context stack,
* - a filter stack,
- * - a delegate stack.
+ * - a delegate stack,
+ * - a template override stack.
*
* As such, it is able to:
*
@@ -51,18 +52,14 @@ extern BOOL GRMustacheRuntimeDidCatchNSUndefinedKeyException;
* - perform a key lookup in the context stack.
* - perform a key lookup in the filter stack.
* - let template and tag delegates interpret rendered values.
+ * - let partial templates override rendering elements.
*/
@interface GRMustacheRuntime : NSObject {
- BOOL _parentHasContext;
- BOOL _parentHasFilter;
- BOOL _parentHasTemplateDelegate;
- BOOL _parentHasTemplateOverride;
- GRMustacheRuntime *_parent;
GRMustacheTemplate *_template;
- id<GRMustacheTemplateDelegate> _templateDelegate;
- GRMustacheTemplateOverride *_templateOverride;
- id _contextObject;
- id _filterObject;
+ NSArray *_contextStack;
+ NSArray *_filterStack;
+ NSArray *_delegateStack;
+ NSArray *_templateOverrideStack;
}
/**
@@ -89,11 +86,8 @@ extern BOOL GRMustacheRuntimeDidCatchNSUndefinedKeyException;
+ (id)valueForKey:(NSString *)key inObject:(id)object GRMUSTACHE_API_INTERNAL;
/**
- * Returns a GRMustacheRuntime object whose:
- *
- * - context stack is empty,
- * - delegate stack is empty,
- * - filter stack is initialized with the filter library.
+ * Returns a GRMustacheRuntime object with empty stacks, but the filter stack,
+ * initialized with the filter library.
*
* This method is only used by GRMustacheRuntimeTest.
*
@@ -104,38 +98,24 @@ extern BOOL GRMustacheRuntimeDidCatchNSUndefinedKeyException;
+ (id)runtime GRMUSTACHE_API_INTERNAL;
/**
- * Returns a GRMustacheRuntime object whose:
- *
- * - context stack is initialized with _contextObject_,
- * - delegate stack is initialized with _template_'s delegate,
- * - filter stack is initialized with the filter library.
- *
- * @param template a template
- * @param contextObject a context object
- *
- * @return A GRMustacheRuntime object.
+ * Returns a GRMustacheRuntime object with empty stacks but:
*
- * @see GRMustacheFilterLibrary
- * @see -[GRMustacheTemplate renderObject:withFilters:]
- */
-+ (id)runtimeWithTemplate:(GRMustacheTemplate *)template contextObject:(id)contextObject GRMUSTACHE_API_INTERNAL;
-
-/**
- * Returns a GRMustacheRuntime object whose:
+ * - the context stack is initialized with _contextStack_,
+ * - the delegate stack is initialized with _template_'s delegate,
+ * - the filter stack is initialized with the filter library.
*
- * - context stack is initialized with objects in _contextObjects_,
- * - delegate stack is initialized with _template_'s delegate,
- * - filter stack is initialized with the filter library.
+ * Object at index 0 in contextStack is the top of the stack (the first queried
+ * object when looking for a key).
*
* @param template a template
- * @param contextObject a context object
+ * @param contextStack a context stack
*
* @return A GRMustacheRuntime object.
*
* @see GRMustacheFilterLibrary
* @see -[GRMustacheTemplate renderObjectsFromArray:withFilters:]
*/
-+ (id)runtimeWithTemplate:(GRMustacheTemplate *)template contextObjects:(NSArray *)contextObjects GRMUSTACHE_API_INTERNAL;
++ (id)runtimeWithTemplate:(GRMustacheTemplate *)template contextStack:(NSArray *)contextStack GRMUSTACHE_API_INTERNAL;
/**
* Returns a GRMustacheRuntime object identical to the receiver, but for the
View
3  src/classes/GRMustacheTemplate.h
@@ -457,6 +457,9 @@
/**
* Renders a template with a context stack initialized with an array of objects.
*
+ * The last object in the array will be the first queried when performing a key
+ * lookup.
+ *
* @param objects An array of context objects for interpreting Mustache tags.
* @param filters An object that provides custom filters.
*
View
10 src/classes/GRMustacheTemplate.m
@@ -187,7 +187,7 @@ - (NSString *)renderObject:(id)object
- (NSString *)renderObject:(id)object withFilters:(id)filters
{
NSMutableString *buffer = [NSMutableString string];
- GRMustacheRuntime *runtime = [GRMustacheRuntime runtimeWithTemplate:self contextObject:object];
+ GRMustacheRuntime *runtime = [GRMustacheRuntime runtimeWithTemplate:self contextStack:(object ? [NSArray arrayWithObject:object] : nil)];
runtime = [runtime runtimeByAddingFilterObject:filters];
[self renderInBuffer:buffer withRuntime:runtime];
return buffer;
@@ -210,8 +210,14 @@ - (NSString *)renderObjectsInArray:(NSArray *)objects withFilters:(id)filters
- (NSString *)renderObjectsFromArray:(NSArray *)objects withFilters:(id)filters
{
+ // GRMustacheRuntime contextStack is in reversed order
+ NSMutableArray *contextStack = [NSMutableArray arrayWithCapacity:objects.count];
+ for (id object in [objects reverseObjectEnumerator]) {
+ [contextStack addObject:object];
+ }
+
NSMutableString *buffer = [NSMutableString string];
- GRMustacheRuntime *runtime = [GRMustacheRuntime runtimeWithTemplate:self contextObjects:objects];
+ GRMustacheRuntime *runtime = [GRMustacheRuntime runtimeWithTemplate:self contextStack:contextStack];
runtime = [runtime runtimeByAddingFilterObject:filters];
[self renderInBuffer:buffer withRuntime:runtime];
return buffer;
Please sign in to comment.
Something went wrong with that request. Please try again.