diff --git a/README.md b/README.md index f13b69df..d6454737 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ What you get **Compatibility with other Mustache implementations**: [Mustache specification v1.1.2](https://github.com/mustache/spec) conformance, and a touch of [Handlebars.js](https://github.com/wycats/handlebars.js) (details in [guides/flavors.md](GRMustache/blob/master/guides/flavors.md)). -**Compatibility with previous GRMustache versions**: update GRMustache, enjoy performance improvements and bugfixes, and don't change a line of your code. +**Compatibility with previous GRMustache versions**: update GRMustache, enjoy performance improvements and bugfixes, and don't change a line of your code. Check the [release notes](RELEASE_NOTES.md). **Number and date formatting.** Handy, and built-in. diff --git a/guides/flavors.md b/guides/flavors.md index 663a04e2..2dafe678 100644 --- a/guides/flavors.md +++ b/guides/flavors.md @@ -20,7 +20,7 @@ How to choose a flavor The only difference so far between the two flavors implementation lies in the syntax for key paths: genuine Mustache reads `{{foo.bar.baz}}`, Handlebars reads `{{foo/bar/baz}}`, and even `{{../foo/bar/baz}}`. -If your templates do not use compound key paths, you can ignore this guide entirely. +If your templates do not use compound key paths, you can [skip](forking.md) this guide entirely. If you are designing new templates from scratch, we encourage you writing your templates in the genuine Mustache flavor. Beware that GRMustache defaults to Handlebars: keep on reading. diff --git a/guides/runtime/booleans.md b/guides/runtime/booleans.md index 24708cf0..f1ffa46d 100644 --- a/guides/runtime/booleans.md +++ b/guides/runtime/booleans.md @@ -26,7 +26,7 @@ We'll first talk about some simple cases. We'll then discuss caveats. The simplest way to provide booleans to GRMustache is to provide objects returned by the `[NSNumber numberWithBool:]` method: NSString *templateString = @"{{#pretty}}whistle{{/pretty}}"; - GRMustacheTemplate *template = [GRMustacheTemplate parseString:templateString error:nil]; + GRMustacheTemplate *template = [GRMustacheTemplate parseString:templateString error:NULL]; // @"whistle" [template renderObject:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] @@ -106,7 +106,7 @@ For the very same reason, you should not use your property getters in templates: // Note the use of the property getter, this time NSString *templateString = @"{{#isPretty}}whistle{{/isPretty}}"; - GRMustacheTemplate *template = [GRMustacheTemplate parseString:templateString error:nil]; + GRMustacheTemplate *template = [GRMustacheTemplate parseString:templateString error:NULL]; // @"whistle" [template renderObject:dave]; diff --git a/guides/runtime/context_stack.md b/guides/runtime/context_stack.md index 1ebebeee..23e5d96b 100644 --- a/guides/runtime/context_stack.md +++ b/guides/runtime/context_stack.md @@ -41,7 +41,7 @@ For instance, the following code will ask `@"foo"` for the key `XXX`. The string [GRMustacheTemplate renderObject:@"foo" fromString:@"{{XXX}}" - error:nil]; + error:NULL]; When debugging your project, those exceptions may become a real annoyance, because you tell your debugger to stop on every Objective-C exceptions. diff --git a/guides/template_loaders.md b/guides/template_loaders.md index 0dbe7102..a346b82e 100644 --- a/guides/template_loaders.md +++ b/guides/template_loaders.md @@ -1,4 +1,143 @@ +[up](../../../../GRMustache), [next](runtime.md) + Template loaders ================ -TODO +GRMustache provides [convenient methods](templates.md) for loading UTF8-encoded templates and partials from the file system. + +However, we may have more needs: your templates and partials hierarchy may not be stored in the file system. If they are, they may not be UTF8-encoded. + +This is where the GRMustacheTemplateLoader class comes in. GRMustacheTemplateLoader objects are generally initialized with a template source, a location where to load templates from. Their role is then to provide template strings whenever a template or a partial is needed. + +Loading templates from the file system +-------------------------------------- + +GRMustacheTemplateLoader ships with the following class methods: + + // Loads templates and partials from a directory, with "mustache" extension, encoded in UTF8 (from MacOS 10.6 and iOS 4.0) + + (id)templateLoaderWithBaseURL:(NSURL *)url; + + // Loads templates and partials from a directory, with provided extension, encoded in UTF8 (from MacOS 10.6 and iOS 4.0) + + (id)templateLoaderWithBaseURL:(NSURL *)url + extension:(NSString *)ext; + + // Loads templates and partials from a directory, with provided extension, encoded in provided encoding (from MacOS 10.6 and iOS 4.0) + + (id)templateLoaderWithBaseURL:(NSURL *)url + extension:(NSString *)ext + encoding:(NSStringEncoding)encoding; + + // Loads templates and partials from a directory, with "mustache" extension, encoded in UTF8 + + (id)templateLoaderWithDirectory:(NSString *)path; + + // Loads templates and partials from a directory, with provided extension, encoded in UTF8 + + (id)templateLoaderWithDirectory:(NSString *)path + extension:(NSString *)ext; + + // Loads templates and partials from a directory, with provided extension, encoded in provided encoding + + (id)templateLoaderWithDirectory:(NSString *)path + extension:(NSString *)ext + encoding:(NSStringEncoding)encoding; + + // Loads templates and partials from a bundle, with "mustache" extension, encoded in UTF8 + + (id)templateLoaderWithBundle:(NSBundle *)bundle; + + // Loads templates and partials from a bundle, with provided extension, encoded in UTF8 + + (id)templateLoaderWithBundle:(NSBundle *)bundle + extension:(NSString *)ext; + + // Loads templates and partials from a bundle, with provided extension, encoded in provided encoding + + (id)templateLoaderWithBundle:(NSBundle *)bundle + extension:(NSString *)ext + encoding:(NSStringEncoding)encoding; + +For instance: + + GRMustacheTemplateLoader *loader = [GRMustacheTemplate templateLoaderWithBaseURL:...]; + +You may now load a template from its location: + + GRMustacheTemplate *template = [loader parseTemplateNamed:@"document" error:NULL]; + +You may also have the loader parse a template string. Only partials would then be loaded from the loader's location: + + GRMustacheTemplate *template = [loader parseString:@"..." error:NULL]; + +The rendering is done as usual: + + NSString *rendering = [template renderObject:...]; + +Other sources for templates +--------------------------- + +GRMustache allows you to subclass the GRMustacheTemplateLoader in order to load templates from any location. + +We provide below the implementation of a template loader which loads partials from a dictionary containing template strings. + +The header file: + + #import "GRMustache.h" + + @interface DictionaryTemplateLoader : GRMustacheTemplateLoader + + (id)loaderWithDictionary:(NSDictionary *)templatesByName; + @end + +In our implementation file, import the `GRMustacheTemplateLoader_protected.h` header, dedicated to GRMustacheTemplateLoader subclasses: + + #import "GRMustacheTemplateLoader_protected.h" + + @interface DictionaryTemplateLoader() + @property (nonatomic, retain) NSDictionary *templatesByName; + @end + + @implementation DictionaryTemplateLoader + @synthetise templatesByName; + + + (id)loaderWithDictionary:(NSDictionary *)templatesByName { + // initWithExtension:encoding: is the designated initializer. + // provide it with some values, even if we won't use them. + DictionaryTemplateLoader *loader = [[[self alloc] initWithExtension:nil encoding:NSUTF8StringEncoding] autorelease]; + loader.templatesByName = templatesByName; + return loader; + } + + - (void)dealloc { + self.templatesByName = nil; + [super dealloc]; + } + +Now let's implement the `templateIdForTemplateNamed:relativeToTemplateId:` method. + +Provided with a partial name that comes from a `{{>name}}` mustache tag, it should return an object which uniquely identifies a template. In our case, we ignore the second argument that would come in handy when implementing a partial hierarchy. However, the template name looks like a perfect way to identify the partials: + + - (id)templateIdForTemplateNamed:(NSString *)name relativeToTemplateId:(id)baseTemplateId { + return name; + } + +And finally, we have to provide template strings: + + - (NSString *)templateStringForTemplateId:(id)templateId error:(NSError **)outError { + return [self.templatesByName objectForKey:templateId]; + } + + @end + +Now we may instanciate one: + + NSDictionary *templates = [NSDictionary dictionaryWithObject:@"It works!" forKey:@"partial"]; + DictionaryTemplateLoader *loader = [DictionaryTemplateLoader loaderWithDictionary:templates]; + +Then load templates from it: + + GRMustacheTemplate *template1 = [loader parseString:@"{{>partial}}" error:NULL]; + GRMustacheTemplate *template2 = [loader parseTemplateNamed:@"partial" error:NULL]; + +And finally render: + + [template1 render]; // "It works!" + [template2 render]; // "It works!" + + +Flavors +------- + +Remember GRMustache supports two flavors of the Mustache language: check [guides/flavors.md](flavors.md) diff --git a/guides/templates.md b/guides/templates.md index 0c4003f4..8fb3b7bf 100644 --- a/guides/templates.md +++ b/guides/templates.md @@ -1,4 +1,4 @@ -[up](../../../../GRMustache), [next](runtime.md) +[up](../../../../GRMustache), [next](template_loaders.md) Templates ========= @@ -123,4 +123,4 @@ More loading options All methods above load UTF8-encoded templates and partials from disk. If this does not fulfill your needs, check [guides/template_loaders.md](template_loaders.md) -[up](../../../../GRMustache), [next](runtime.md) +[up](../../../../GRMustache), [next](template_loaders.md)