Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

file 139 lines (89 sloc) 5.185 kb

up, next

Filters

Filters are not yet part of the Mustache specification. You thus need to explicitely opt-in in order to use them, with the {{%FILTERS}} special "pragma" tag in your templates.

The topic of filters is currently under discussion with other implementors of Mustache. A detailed explanation of the ideas behind the filtering API described below is available at WhyMustacheFilters.md.

Overview

You apply a filter just like calling a function, with parentheses:

  • {{%FILTERS}}My name is {{ uppercase(name) }} would render My name is ARTHUR, provided with "Arthur" as a name.

  • Filters can chain: {{ uppercase(reversed(name)) }} would render RUHTRA.

  • Filters can apply to compound key paths: {{ uppercase(person.name) }}.

  • You can extract values from filtered values: {{ last(persons).name }}.

  • You can filter sections as well : {{^ isEmpty(people) }}...{{/ isEmpty(people) }} renders if the people collection is not empty.

    For brevity's sake, closing section tags can be empty: {{^ isEmpty(people) }}...{{/}} is valid.

Standard filters library

GRMustache ships with a bunch of already implemented filters:

  • isEmpty

    Returns YES if the input is nil, [NSNull null], or an empty enumerable object, or an empty string. Returns NO otherwise.

  • isBlank

    Returns YES if the input is nil, [NSNull null], or an empty enumerable object, or a string made of zero or more white space characters (space, tabs, newline). Returns NO otherwise.

  • capitalized

    Given "johannes KEPLER", it returns "Johannes Kepler".

  • lowercase

    Given "johannes KEPLER", it returns "johannes kepler".

  • uppercase

    Given "johannes KEPLER", it returns "JOHANNES KEPLER".

Defining your own filters

You can implement your own filters with objects that conform to the GRMustacheFilter protocol.

This protocol defines a single required method:

@protocol GRMustacheFilter <NSObject>
@required
- (id)transformedValue:(id)object;
@end

You can for instance declare a filter that outputs numbers as percentages:

@interface PercentFilter : NSObject<GRMustacheFilter>
@end

@implementation PercentFilter
- (id)transformedValue:(id)object
{
    NSNumberFormatter *percentNumberFormatter = [[NSNumberFormatter alloc] init];
    percentNumberFormatter.numberStyle = kCFNumberFormatterPercentStyle;
    return [numberFormatter stringFromNumber:object];
}
@end

id percentFilters = [[PercentFilter alloc] init];

Starting iOS4 and MacOS 10.6, the Objective-C language provides us with blocks. This can relieve the burden of declaring a full class for each filter:

id percentFilter = [GRMustacheFilter filterWithBlock:^id(id object) {
    NSNumberFormatter *percentNumberFormatter = [[NSNumberFormatter alloc] init];
    percentNumberFormatter.numberStyle = kCFNumberFormatterPercentStyle;
    return [numberFormatter stringFromNumber:object];
}];

Now, let's have GRMustache know about your custom filter, and use it:

// Prepare the data
float gain = 0.5;
NSDictionary *data = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:gain] forKey:@"gain"];

// Prepare the filters
NSDictionary *filters = [NSDictionary dictionaryWithObject:percentFilter forKey:@"percent"];

// Renders @"Enjoy your 50% productivity bump!"
NSString *templateString = @"{{%FILTERS}}Enjoy your {{ percent(gain) }} productivity bump!";
NSString *rendering = [GRMustacheTemplate renderObject:data
                                           withFilters:filters
                                            fromString:templateString
                                                 error:NULL];

Filters namespaces

Just as you can provide an object hierarchy for rendered values, and extract person.pet.name from it, you can provide filters as an object hierarchy, and "namespace" your filters. For instance, let's declare the math.abs filter, and render {{ math.abs(x) }}:

id absFilter = [GRMustacheFilter filterWithBlock:^id(id object) {
    return [NSNumber numberWithInt: abs([object intValue])];
}];
NSDictionary *mathFilters = [NSDictionary dictionaryWithObject:absFilter forKey:@"abs"];
NSDictionary *filters = [NSDictionary dictionaryWithObject:mathFilters forKey:@"math"];

[GRMustacheTemplate renderObject:...
                     withFilters:filters
                      fromString:@"{{%FILTERS}}{{math.abs(x)}}"
                           error:NULL];

Filters exceptions

Should a filter be missing, or should the matching object not conform to the GRMustacheFilter protocol, GRMustache will raise an exception of name GRMustacheFilterException.

The message describes the exact place where the error occur has occurred:

Missing filter for key `f` in tag `{{ f(foo) }}` at line 13 of /path/to/template.

Object for key `f` in tag `{{ f(foo) }}` at line 13 of /path/to/template does not conform to GRMustacheFilter protocol: "blah"

up, next

Something went wrong with that request. Please try again.