-
Notifications
You must be signed in to change notification settings - Fork 644
/
GBTemplateHandler.m
148 lines (120 loc) · 4.92 KB
/
GBTemplateHandler.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//
// GBTemplateHandler.m
// appledoc
//
// Created by Tomaz Kragelj on 17.11.10.
// Copyright (c) 2010 __MyCompanyName__. All rights reserved.
//
#import "RegexKitLite.h"
#import "GRMustache.h"
#import "GBDictionaryTemplateLoader.h"
#import "GBTemplateHandler.h"
static NSString *kGBSectionKey = @"section";
static NSString *kGBNameKey = @"name";
static NSString *kGBValueKey = @"value";
#pragma mark -
@interface GBTemplateHandler ()
- (void)clearParsedValues;
- (BOOL)validateSectionData:(NSDictionary *)data withTemplate:(NSString *)template;
- (NSUInteger)lineOfSectionData:(NSDictionary *)data withinTemplate:(NSString *)template;
@end
#pragma mark -
@implementation GBTemplateHandler
#pragma mark Initialization & disposal
+ (id)handler {
return [[[self alloc] init] autorelease];
}
- (id)init {
self = [super init];
if (self) {
_templateSections = [[NSMutableDictionary alloc] init];
}
return self;
}
#pragma mark Parsing handling
- (BOOL)parseTemplateFromPath:(NSString *)path error:(NSError **)error {
GBLogVerbose(@"Parsing template from %@...", path);
[self clearParsedValues];
NSString *template = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:error];
if (!template) {
if (error) GBLogNSError(*error, @"Loading template %@ failed!", path);
return NO;
}
return [self parseTemplate:template error:error];
}
- (BOOL)parseTemplate:(NSString *)template error:(NSError **)error {
[self clearParsedValues];
if ([template length] == 0) return YES;
NSString *regex = @"(Section\\s+(\\w+)\\s+(.*?)\\s+EndSection)";
NSString *clean = [template copy];
while (YES) {
// Get all components of the regex.
NSRange searchRange = NSMakeRange(0, [clean length]);
NSDictionary *sectionData = [clean dictionaryByMatchingRegex:regex options:RKLDotAll range:searchRange error:nil withKeysAndCaptures:kGBSectionKey, 1, kGBNameKey, 2, kGBValueKey, 3, nil];
if ([sectionData count] == 0) break;
// If section data is valid, use it.
if ([self validateSectionData:sectionData withTemplate:template]) {
NSString *name = [sectionData objectForKey:kGBNameKey];
NSString *value = [[sectionData objectForKey:kGBValueKey] stringByTrimmingWhitespaceAndNewLine];
[_templateSections setObject:value forKey:name];
}
// If the section is valid, log it.
NSUInteger line = [self lineOfSectionData:sectionData withinTemplate:template];
GBLogDebug(@"Found section template %@ at line %ld...", [sectionData objectForKey:kGBNameKey], line);
// Get the range of the regex within the clean string and remove the substring from it.
NSString *section = [sectionData objectForKey:kGBSectionKey];
NSRange range = [clean rangeOfString:section];
NSString *prefix = [[clean substringToIndex:range.location] stringByTrimmingWhitespaceAndNewLine];
NSString *suffix = [[clean substringFromIndex:range.location + range.length] stringByTrimmingWhitespaceAndNewLine];
NSString *delimiter = ([prefix length] > 0 && [suffix length] > 0) ? @"\n" : @"";
clean = [NSString stringWithFormat:@"%@%@%@", prefix, delimiter, suffix];
if ([clean length] == 0) break;
}
// Prepare template string and warn if it's empty.
if ([clean length] == 0) GBLogWarn(@"Template contains empty string (with %ld template sections)!", [_templateSections count]);
_templateString = [clean copy];
// Prepare template that will be used for rendering output.
if ([_templateString length] != 0) {
GBDictionaryTemplateLoader *loader = [GBDictionaryTemplateLoader loaderWithDictionary:_templateSections];
_template = [loader parseString:_templateString error:error];
return (_template != nil);
}
return YES;
}
#pragma Rendering handling
- (NSString *)renderObject:(id)object {
GBLogVerbose(@"Rendering %@...", [[object description] normalizedDescription]);
if (!_template) {
GBLogWarn(@"No template loaded or parsed, ignoring redering!");
return @"";
}
return [_template renderObject:object];
}
#pragma mark Helper methods
- (BOOL)validateSectionData:(NSDictionary *)data withTemplate:(NSString *)template {
NSString *name = [data objectForKey:kGBNameKey];
if ([name length] == 0) {
NSUInteger line = [self lineOfSectionData:data withinTemplate:template];
GBLogWarn(@"Unnamed section found at line %ld, ignoring!", line);
return NO;
}
NSString *value = [[data objectForKey:kGBValueKey] stringByTrimmingWhitespace];
if ([value length] == 0) {
NSUInteger line = [self lineOfSectionData:data withinTemplate:template];
GBLogWarn(@"Empty section %@ found at line %ld, ignoring!", name, line);
return NO;
}
return YES;
}
- (NSUInteger)lineOfSectionData:(NSDictionary *)data withinTemplate:(NSString *)template {
NSString *section = [data objectForKey:kGBSectionKey];
NSRange range = [template rangeOfString:section];
return [template numberOfLinesInRange:NSMakeRange(0, range.location)];
}
- (void)clearParsedValues {
GBLogDebug(@"Clearing parsed values...");
_template = nil;
_templateString = @"";
[_templateSections removeAllObjects];
}
@end