-
Notifications
You must be signed in to change notification settings - Fork 190
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
Pluralizing/singularizing strings? #50
Comments
Hi Ryan! Thanks for the nice comments! I'd follow the same idea as the This pattern fits well your own template: "flavor" is part of the template content, just as "Hello" above. But instead of rendering "goût", we want to render "flavor" or "flavors" depending on the flavors count. So we'll render the following template:
// Let's first assume a category on NSString that performs the pluralization:
@interface NSString(Pluralize)
- (NSString *)pluralize:(NSUInteger)count;
@end
@implementation NSString(Pluralize)
- (NSString *)pluralize:(NSUInteger)count
{
// Naive implementation
if (count < 2) return self;
return [self stringByAppendingString:@"s"];
}
@end
// Now the actual rendering:
id data = @{
@"dogCount": @1,
@"catCount": @2,
// The pluralize filter...
@"pluralize": [GRMustacheFilter filterWithBlock:^id(NSNumber *countNumber) {
// ... extracts the count from its argument...
NSUInteger count = [countNumber unsignedIntegerValue];
// ... and actually returns an object that processes the section it renders for:
return [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError *__autoreleasing *error) {
// First get the word to pluralize by performing a first "classic" rendering of the section...
NSString *word = [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
// ... and finally use our count
return [word pluralize:count];
}];
}],
};
NSString *templateString = @"I have {{dogCount}} {{#pluralize(dogCount)}}dog{{/}} and {{catCount}} {{#pluralize(catCount)}}cat{{/}}.";
NSString *rendering = [GRMustacheTemplate renderObject:data fromString:templateString error:NULL]; The result is This technique is generally very useful in GRMustache: having filters that return rendering objects. Note that you can now even pluralize dynamic words: I hope this approach looks sensible to you! |
Better reading your initial message, I realize |
Extending the topic: Such general purpose tools may want to enter your own library of reusable components, that would extend the standard library. The way to achieve this is to use GRMustacheConfiguration class: // Add `pluralize` to the standard GRMustache library,
// once and for all for the whole application:
id myLibrary = @{
@"pluralize": [GRMustacheFilter filterWithBlock:^id(NSNumber *countNumber) {
NSUInteger count = [countNumber unsignedIntegerValue];
return [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError *__autoreleasing *error) {
NSString *word = [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
return [word pluralize:count];
}];
}],
};
GRMustacheContext *baseContext = [GRMustacheConfiguration defaultConfiguration].baseContext;
baseContext = [baseContext contextByAddingObject:myLibrary];
[GRMustacheConfiguration defaultConfiguration].baseContext = baseContext;
// And now render, assuming `pluralize` is generally available.
id data = @{
@"dogCount": @1,
@"catCount": @2,
};
NSString *templateString = @"I have {{dogCount}} {{#pluralize(dogCount)}}dog{{/}} and {{catCount}} {{#pluralize(catCount)}}cat{{/}}.";
NSString *rendering = [GRMustacheTemplate renderObject:data fromString:templateString error:NULL]; |
Thanks very much for the quick and extensive response. Yes, I've implemented it in combination with @mattt's InflectorKit, and it works great:
Thanks for the info about extending the standard library. That'll come in handy down the line. 👍 |
It's not easy to find a good enough title for this kind of guide. Why would anybody click a "combining filters and rendering objects" without any clue on what he can achieve with such a combination? Anyway, I may use your use case in the FAQ : "Can I pluralize/singularize words? Yesir!" -> boom link to our sample code :-) I'm quite honored that GRMustache is member of the happy few third-party libraries you dare integrate, along with the amazingly useful ones of @mattt :-) Happy Mustache, Ryan! |
That sounds like a better idea. Thanks again! 👨 |
It seems like a fairly common requirement to have a word that needs to be singular or plural based on some value, e.g:
Right now the only way I've got this working is to create an 'isOne' filter. I don't like this workaround because it introduces a conditional into the template, which seems like it negates the idea of 'logicless templates':
Another issue here is that not all words are pluralized simply by adding an 's', lengthening the template into having to deal with singular and plural cases individually.
Ideally I'd like to pass the count to a rendered block:
The issue with this at the moment is that, as far as I can tell, rendered blocks can't accept arguments. Variadic filters can, but they can't accept literals:
Any ideas on how to move ahead with this? Perhaps someone else has run into this scenario?
Also, thanks for the library. Usually I avoid depending on third parties, but your library is so well implemented that I couldn't pass it up. 👍
The text was updated successfully, but these errors were encountered: