Closed NightFox7 closed 10 years ago
Hi
No, there is no such feature today. You can use the first
and last
keys of NSArray, though.
I never had such a need... Would you mind giving an example where such a possibility would be useful?
All right. I'm closing this issue right now.
GRMustache implements the mustache templating language as defined by https://github.com/mustache/spec. And the spec, so far, as no support for accessing array elements by index.
I recommend you open an issue in the very repository of the spec: https://github.com/mustache/spec/issues
Sorry I didn't answer you sooner. As for the example that you demanded. Well, let's say I have 2 NSArray. Each has some information about a certain object like so:
array1 = [ ['name': 'John', 'lastname': 'doe'], ['firtname': 'John2', 'lastname': 'doe2'] ];
array2 = [ ['age': 20], ['age': 25] ];
I want to display:
John doe is 20 years old.
John2 doe2 is 25 years old.
So my idea was to go through the first array then use the index to get the required object from the second array.
Do you have an alternative way without using the index?
I get it. We could imagine some zip
filter, that you could use in a template like:
{{# zip(array1, array2) }}
{{ name }} {{ lastname }} is {{ age }} years old.
{{/ }}
It's quite possible, using [GRMustacheFilter variadicFilterWithBlock:]
. Yet the usual advice in these cases is to give the template data it can render. The template would look like:
{{# zipped_array1_array2) }}
{{ name }} {{ lastname }} is {{ age }} years old.
{{/ }}
Where zipped_array1_array2
would be pre-computed, or the result of a computed property based on array1 and array2. It is simpler to read and simpler to understand.
Yet a zip
filter would be handy in the GRMustache standard library, thanks for the idea :-) You may try to write it if you want :-)
Thanks @groue for your answer. I am gonna try to implement the zip filter that you suggested and get back to you when it's done.
GRMustache 7.2 has shipped, with built-in zip
filter (documentation). Thanks for your contribution :smile:
The introduction of the zip
filter in the standard library has generated backward compatibility issues (see issue #82).
GRMustache v7.3.0 has shipped without it, in order to restore compatibility.
Below you'll find the documentation for the discontinued zip
filter, and its Objective-C code:
zip
Usage:
{{# zip(list1, list2, ...) }}...{{/}}
The zip
filter iterates several lists all at once. On each step, one object from each input list enters the rendering context, and makes its own keys available for rendering.
Document.mustache
:
{{# zip(users, teams, scores) }}
- {{ name }} ({{ team }}): {{ score }} points
{{/}}
data.json
:
{
"users": [
{ "name": "Alice" },
{ "name": "Bob" },
],
"teams": [
{ "team": "iOS" },
{ "team": "Android" },
],
"scores": [
{ "score": 100 },
{ "score": 200 },
]
}
Rendering:
- Alice (iOS): 100 points
- Bob (Android): 200 points
In the example above, the first step has consumed (Alice, iOS and 100), and the second one (Bob, Android and 200):
The zip
filter renders a section as many times as there are elements in the longest of its argument: exhausted lists simply do not add anything to the rendering context.
id zipFilter = [GRMustacheFilter variadicFilterWithBlock:^id(NSArray *arguments) {
// GRMustache generally identifies collections as objects conforming
// to NSFastEnumeration, excluding NSDictionary.
//
// Let's validate our arguments first.
for (id argument in arguments) {
if (![argument respondsToSelector:@selector(countByEnumeratingWithState:objects:count:)] || [argument isKindOfClass:[NSDictionary class]]) {
return [GRMustacheRendering renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
if (error) {
*error = [NSError errorWithDomain:GRMustacheErrorDomain code:GRMustacheErrorCodeRenderingError userInfo:@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"zip filter in tag %@ requires all its arguments to be enumerable. %@ is not.", tag, argument] }];
}
return nil;
}];
}
}
// Turn NSFastEnumeration arguments into enumerators. This is
// because enumerators can be iterated all together, when
// NSFastEnumeration objects can not.
NSMutableArray *enumerators = [NSMutableArray array];
for (id argument in arguments) {
if ([argument respondsToSelector:@selector(objectEnumerator)]) {
// Assume objectEnumerator method returns what we need.
[enumerators addObject:[argument objectEnumerator]];
} else {
// Turn NSFastEnumeration argument into an array,
// and extract enumerator from the array.
NSMutableArray *array = [NSMutableArray array];
for (id object in argument) {
[array addObject:object];
}
[enumerators addObject:[array objectEnumerator]];
}
}
// Build an array of objects which will perform custom rendering.
NSMutableArray *renderingObjects = [NSMutableArray array];
while (YES) {
// Extract from all iterators the objects that should enter the
// rendering context at each iteration.
//
// Given the [1,2,3], [a,b,c] input collections, those objects
// would be [1,a] then [2,b] and finally [3,c].
NSMutableArray *objects = [NSMutableArray array];
for (NSEnumerator *enumerator in enumerators) {
id object = [enumerator nextObject];
if (object) {
[objects addObject:object];
}
}
// All iterators have been enumerated: stop
if (objects.count == 0) {
break;
}
// Build a rendering object which extends the rendering context
// before rendering the tag.
id<GRMustacheRendering> renderingObject = [GRMustacheRendering renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError **error) {
for (id object in objects) {
context = [context contextByAddingObject:object];
}
return [tag renderContentWithContext:context HTMLSafe:HTMLSafe error:error];
}];
[renderingObjects addObject:renderingObject];
}
return renderingObjects;
}];
Is there a way to get an element from an array using its index?