Skip to content
Browse files

Fully expose and document GRMustacheContext

  • Loading branch information...
1 parent 5c6ebaa commit df2bdc84839f0bc3e733bc3cf2ffdfeedd566933 @groue committed Dec 7, 2010
View
1 Classes/GRMustacheContext.h
@@ -29,4 +29,5 @@
+ (id)contextWithObject:(id)object;
+ (id)contextWithObjects:(id)object, ...;
- (GRMustacheContext *)contextByAddingObject:(id)object;
+- (id)valueForKey:(NSString *)key;
@end
View
2 Classes/GRMustacheContext.m
@@ -193,7 +193,7 @@ - (void)dealloc {
- (id)valueForKeyComponent:(NSString *)key foundInContext:(GRMustacheContext **)outContext {
// value by selector
- SEL renderingSelector = NSSelectorFromString([NSString stringWithFormat:@"%@Section:withObject:", key]);
+ SEL renderingSelector = NSSelectorFromString([NSString stringWithFormat:@"%@Section:withContext:", key]);
if ([object respondsToSelector:renderingSelector]) {
return [GRMustacheLambdaSelectorWrapper helperWithObject:object selector:renderingSelector];
}
View
3 Classes/GRMustacheLambda.h
@@ -21,9 +21,10 @@
// THE SOFTWARE.
#import "GRMustacheSection.h"
+#import "GRMustacheContext.h"
#if NS_BLOCKS_AVAILABLE
-typedef NSString *(^GRMustacheRenderingBlock)(GRMustacheSection *, id);
+typedef NSString *(^GRMustacheRenderingBlock)(GRMustacheSection*, GRMustacheContext*);
id GRMustacheLambdaBlockMake(GRMustacheRenderingBlock block);
typedef NSString *(^GRMustacheRenderer)(id object) __attribute__((deprecated));
View
79 README.md
@@ -357,7 +357,7 @@ Imagine that, in the following template, you wish the `link` sections to be rend
<ul>
{{#people}}
- <li>{{#link}}{{name}}{{#/link}}</li>
+ <li>{{#link}}{{name}}{{/link}}</li>
{{/people}}
</ul>
@@ -372,42 +372,36 @@ GRMustache provides you with two ways in order to achieve this behavior. The fir
### Lambda blocks
-**NB: Lambda blocks are not available until MacOS 10.6, and iOS 4.0.**
+*Note that lambda blocks are not available until MacOS 10.6, and iOS 4.0.*
You will provide in the context an object built with the GRMustacheLambdaBlockMake function. This function takes a block which returns the string that should be rendered, as in the example below:
// prepare our link lambda block
- id linkLambda = GRMustacheLambdaBlockMake(^(GRMustacheSection *section, id context) {
+ id linkLambda = GRMustacheLambdaBlockMake(^(GRMustacheSection *section, GRMustacheContext *context) {
return [NSString stringWithFormat:
@"<a href=\"/people/%@\">%@</a>",
[context valueForKey:@"id"], // id of person comes from current context
[section renderObject:context]] // link text comes from the natural rendering of the inner section
});
-- `section` is an object which is able to render the section, provided with a context object.
+- `section` is an object which represent the rendered section.
- `context` is the current rendering context.
-Note that, in case you would need it, the `section` object has a `templateString` property, which contains the litteral inner section, unrendered (`{{tags}}` will not have been expanded).
+The `[section renderObject:context]` expression evaluates with the rendering of the section with the given context.
-The rendering now goes as usual, by providing objects for template keys:
+In case you would need it, the `section` object has a `templateString` property, which contains the litteral inner section, unrendered (`{{tags}}` will not have been expanded).
+
+The final rendering now goes as usual, by providing objects for template keys:
NSArray *people = ...;
[template renderObject:[NSDictionary dictionaryWithObjectsAndKeys:
linkLambda, @"link",
people, @"people",
nil]];
-Note that lambda blocks can be used for whatever you may find relevant. You may, for instance, implement caching:
-
- __block NSString *cache = nil;
- id cacheLambda = GRMustacheLambdaBlockMake(^(GRMustacheSection *section, id context) {
- if (cache == nil) { cache = [section renderObject:context]; }
- return cache;
- });
-
### Helper methods
-Another way to execute code when rendering the `link` sections is to have the context implement the `linkSection:withObject:` selector (generally, implement a method whose name is the name of the section, to which you append `Section:withObject:`).
+Another way to execute code when rendering the `link` sections is to have the context implement the `linkSection:withContext:` selector (generally, implement a method whose name is the name of the section, to which you append `Section:withContext:`).
No block is involved, and this technique works before MacOS 10.6, and iOS 4.0.
@@ -428,27 +422,27 @@ If your model object is designed as such:
@property NSString *id;
@end
-You can declare the `linkSection:withObject` as a category of an object that will be used as a context.
+You can declare the `linkSection:withContext` as a category of an object that will be used as a context.
You may use the Person object itself:
@implementation Person(GRMustache)
- - (NSString*)linkSection:(GRMustacheSection *)section withObject:(id)object {
+ - (NSString*)linkSection:(GRMustacheSection *)section withContext:(GRMustacheContext *)context {
return [NSString stringWithFormat:
@"<a href=\"/people/%@\">%@</a>",
- self.id, // id comes from self
- [section renderObject:object]]; // link text comes from the natural rendering of the inner section
+ self.id, // id comes from self
+ [section renderObject:context]]; // link text comes from the natural rendering of the inner section
}
@end
You may also use the root DataModel object:
@implementation DataModel(GRMustache)
- - (NSString*)linkSection:(GRMustacheSection *)section withObject:(id)object {
+ - (NSString*)linkSection:(GRMustacheSection *)section withContext:(GRMustacheContext *)context {
return [NSString stringWithFormat:
@"<a href=\"/people/%@\">%@</a>",
- [object valueForKey:@"id"], // id of person comes from current context
- [section renderObject:object]]; // link text comes from the natural rendering of the inner section
+ [object valueForKey:@"id"], // id of person comes from current context
+ [section renderObject:context]]; // link text comes from the natural rendering of the inner section
}
@end
@@ -470,11 +464,11 @@ GRMustache allows you to do that, too. First declare a container for your helper
@end
@implementation RenderingHelper
- + (NSString*)linkSection:(GRMustacheSection *)section withObject:(id)object {
+ + (NSString*)linkSection:(GRMustacheSection *)section withContext:(GRMustacheContext *)context {
return [NSString stringWithFormat:
@"<a href=\"/people/%@\">%@</a>",
- [object valueForKey:@"id"], // id of person comes from current context
- [section renderObject:object]]; // link text comes from the natural rendering of the inner section
+ [object valueForKey:@"id"], // id of person comes from current context
+ [section renderObject:context]]; // link text comes from the natural rendering of the inner section
}
@end
@@ -483,12 +477,45 @@ Here we have written class methods because our helper doesn't carry any state. Y
Now let's introduce the GRMustacheContext class. Its role is to help you provide to the template a context which contains both data, and helper methods:
id dataModel = ...;
- id context = [GRMustacheContext contextWithObjects: [RenderingHelper class], dataModel, nil];
+ GRMustacheContext *context = [GRMustacheContext contextWithObjects: [RenderingHelper class], dataModel, nil];
And now we can render:
[template renderObject:context];
+#### Usages of lambdas and helpers
+
+Lambdas and helpers can be used for whatever you may find relevant. We'll base our examples on lambda blocks, but the same patterns apply to helper methods.
+
+You may, for instance, implement caching:
+
+ __block NSString *cache = nil;
+ GRMustacheLambdaBlockMake(^(GRMustacheSection *section, GRMustacheContext *context) {
+ if (cache == nil) { cache = [section renderObject:context]; }
+ return cache;
+ });
+
+You may render another context:
+
+ GRMustacheLambdaBlockMake(^(GRMustacheSection *section, GRMustacheContext *context) {
+ return [section renderObject:[NSDictionary ...]];
+ });
+
+You may render an extended context:
+
+ GRMustacheLambdaBlockMake(^(GRMustacheSection *section, GRMustacheContext *context) {
+ return [section renderObject:[context contextByAddingObject:[NSDictionary ...]]];
+ });
+
+You may implement debugging sections:
+
+ GRMustacheLambdaBlockMake(^(GRMustacheSection *section, GRMustacheContext *context) {
+ NSLog(section.templateString); // log the unrendered section
+ NSLog([section renderObject:context]); // log the rendered section
+ return nil; // don't render anything
+ });
+
+
Template loaders
----------------
View
10 Tests/v1.2/GRMustacheHelperTest.m
@@ -29,15 +29,15 @@ @interface GRMustacheHelperTestContext: NSObject
@implementation GRMustacheHelperTestContext
-- (NSString*)boldSection:(GRMustacheSection *)section withObject:(id)object {
- return [NSString stringWithFormat:@"<b>%@</b>", [section renderObject:object]];
+- (NSString*)boldSection:(GRMustacheSection *)section withContext:(GRMustacheContext *)context {
+ return [NSString stringWithFormat:@"<b>%@</b>", [section renderObject:context]];
}
-+ (NSString*)linkSection:(GRMustacheSection *)section withObject:(id)object {
++ (NSString*)linkSection:(GRMustacheSection *)section withContext:(GRMustacheContext *)context {
return [NSString stringWithFormat:
@"<a href=\"/people/%@\">%@</a>",
- [object valueForKey:@"id"],
- [section renderObject:object]];
+ [context valueForKey:@"id"],
+ [section renderObject:context]];
}
@end
View
10 Tests/v1.2/GRMustacheLambdaBlockTest.m
@@ -27,7 +27,7 @@ @implementation GRMustacheLambdaBlockTest
- (void)testDoesntExecuteWhatItDoesntNeedTo {
__block BOOL dead = NO;
- id dieLambda = GRMustacheLambdaBlockMake(^(GRMustacheSection *section, id context) {
+ id dieLambda = GRMustacheLambdaBlockMake(^(GRMustacheSection *section, GRMustacheContext *context) {
dead = YES;
return @"foo";
});
@@ -42,15 +42,15 @@ - (void)testSectionsReturningLambdasGetCalledWithText {
__block int renderedCalls = 0;
__block NSString *cache = nil;
- id renderedLambda = GRMustacheLambdaBlockMake(^(GRMustacheSection *section, id context) {
+ id renderedLambda = GRMustacheLambdaBlockMake(^(GRMustacheSection *section, GRMustacheContext *context) {
if (cache == nil) {
renderedCalls++;
cache = [section renderObject:context];
}
return cache;
});
- id notRenderedLambda = GRMustacheLambdaBlockMake(^(GRMustacheSection *section, id context) {
+ id notRenderedLambda = GRMustacheLambdaBlockMake(^(GRMustacheSection *section, GRMustacheContext *context) {
return section.templateString;
});
@@ -78,7 +78,7 @@ - (void)testSectionsReturningLambdasGetCalledWithText {
- (void)testSectionLambdasCanRenderCurrentContextInSpecificTemplate {
NSString *templateString = @"{{#wrapper}}{{/wrapper}}";
GRMustacheTemplate *wrapperTemplate = [GRMustacheTemplate parseString:@"<b>{{name}}</b>" error:nil];
- id wrapperLambda = GRMustacheLambdaBlockMake(^(GRMustacheSection *section, id context) {
+ id wrapperLambda = GRMustacheLambdaBlockMake(^(GRMustacheSection *section, GRMustacheContext *context) {
return [wrapperTemplate renderObject:context];
});
NSDictionary *context = [NSDictionary dictionaryWithObjectsAndKeys:
@@ -91,7 +91,7 @@ - (void)testSectionLambdasCanRenderCurrentContextInSpecificTemplate {
- (void)testSectionLambdasCanReturnNil {
NSString *templateString = @"foo{{#wrapper}}{{/wrapper}}bar";
- id wrapperLambda = GRMustacheLambdaBlockMake(^(GRMustacheSection *section, id context) {
+ id wrapperLambda = GRMustacheLambdaBlockMake(^(GRMustacheSection *section, GRMustacheContext *context) {
return (NSString *)nil;
});
NSDictionary *context = [NSDictionary dictionaryWithObject:wrapperLambda forKey:@"wrapper"];

0 comments on commit df2bdc8

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