-
Notifications
You must be signed in to change notification settings - Fork 4
/
CWInflector.mm
156 lines (126 loc) · 5.38 KB
/
CWInflector.mm
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
149
150
151
152
153
154
155
156
/*
An implementation of the Ruby on Rails inflector in Objective-C.
Ciarán Walsh, 2008
See README.mdown for usage info.
Use ⌃R on the following line in TextMate to run tests:
g++ "$TM_FILEPATH" "$(dirname "$TM_FILEPATH")"/RegexKitLite/RegexKitLite.m -licucore -DTEST_INFLECTOR -framework Cocoa -o "${TM_FILEPATH%.*}" && ("${TM_FILEPATH%.*}"; rm "${TM_FILEPATH%.*}")
*/
#import "CWInflector.h"
#import "RegexKitLite/RegexKitLite.h"
@implementation CWInflector
static CWInflector* sharedInstance = nil;
+ (CWInflector*)inflector;
{
return sharedInstance ?: [[self new] autorelease];
}
- (id)init
{
if(sharedInstance)
{
[self release];
}
else if(self = sharedInstance = [[super init] retain])
{
plurals = [NSMutableArray new];
singulars = [NSMutableArray new];
uncountables = [NSMutableArray new];
[self addInflectionsFromFile:[[NSBundle bundleForClass:[self class]] pathForResource:@"inflections" ofType:@"plist"]];
}
return sharedInstance;
}
- (void)dealloc
{
[plurals release];
[singulars release];
[uncountables release];
[super dealloc];
}
- (void)addInflectionsFromFile:(NSString*)path;
{
NSDictionary* inflections = [NSDictionary dictionaryWithContentsOfFile:path];
[plurals addObjectsFromArray:[inflections objectForKey:@"plurals"]];
[singulars addObjectsFromArray:[inflections objectForKey:@"singulars"]];
[uncountables addObjectsFromArray:[inflections objectForKey:@"uncountables"]];
for(NSArray* irregular in [inflections objectForKey:@"irregulars"])
[self addIrregular:[irregular objectAtIndex:0] plural:[irregular objectAtIndex:1]];
}
- (void)addIrregular:(NSString*)singular plural:(NSString*)plural;
{
NSString* pattern = [NSString stringWithFormat:@"(%C)%@$", [singular characterAtIndex:0], [singular substringFromIndex:1]];
NSString* substitution = [NSString stringWithFormat:@"$1%@", [plural substringFromIndex:1]];
[self addPluralPattern:pattern substitution:substitution];
pattern = [NSString stringWithFormat:@"(%C)%@$", [plural characterAtIndex:0], [plural substringFromIndex:1]];
substitution = [NSString stringWithFormat:@"$1%@", [singular substringFromIndex:1]];
[self addSingularPattern:pattern substitution:substitution];
}
- (void)addPluralPattern:(NSString*)pattern substitution:(NSString*)substitution;
{
[plurals addObject:[NSArray arrayWithObjects:pattern,substitution,nil]];
}
- (void)addSingularPattern:(NSString*)pattern substitution:(NSString*)substitution;
{
[singulars addObject:[NSArray arrayWithObjects:pattern,substitution,nil]];
}
- (NSString*)pluralFormOf:(NSString*)singular;
{
if([uncountables containsObject:[singular lowercaseString]])
return singular;
NSEnumerator* enumerator = [plurals reverseObjectEnumerator];
while(NSArray* conversion = [enumerator nextObject])
{
NSString* result = [singular stringByReplacingOccurrencesOfRegex:[conversion objectAtIndex:0] withString:[conversion objectAtIndex:1]];
if(result && ![result isEqualToString:singular])
return result;
}
return singular;
}
- (NSString*)singularFormOf:(NSString*)plural;
{
if([uncountables containsObject:[plural lowercaseString]])
return plural;
NSEnumerator* enumerator = [singulars reverseObjectEnumerator];
while(NSArray* conversion = [enumerator nextObject])
{
NSString* result = [plural stringByReplacingOccurrencesOfRegex:[conversion objectAtIndex:0] withString:[conversion objectAtIndex:1]];
if(result && ![result isEqualToString:plural])
return result;
}
return plural;
}
- (NSString*)humanizedFormOf:(NSString*)word;
{
NSString* result = word;
if([result length] > 3 && [[result substringFromIndex:([result length]-3)] isEqualToString:@"_id"])
result = [result substringToIndex:([result length]-3)];
result = [result stringByReplacingOccurrencesOfString:@"_" withString:@" "];
return [[[result substringToIndex:1] uppercaseString] stringByAppendingString:[result substringFromIndex:1]];
}
@end
@implementation NSString (InflectorAdditions)
- (NSString*)pluralForm { return [[CWInflector inflector] pluralFormOf:self]; }
- (NSString*)singularForm { return [[CWInflector inflector] singularFormOf:self]; }
- (NSString*)humanizedForm { return [[CWInflector inflector] humanizedFormOf:self]; }
@end
#ifdef TEST_INFLECTOR
#include <assert.h>
int main() {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
assert([CWInflector inflector] == [CWInflector inflector]);
NSString* plistPath = [[[NSString stringWithUTF8String:__FILE__] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"inflections.plist"];
[[CWInflector inflector] addInflectionsFromFile:plistPath];
assert([[[CWInflector inflector] pluralFormOf:@"Cat"] isEqualToString:@"Cats"]);
assert([[[CWInflector inflector] pluralFormOf:@"bus"] isEqualToString:@"buses"]);
assert([[[CWInflector inflector] pluralFormOf:@"man"] isEqualToString:@"men"]);
assert([[@"Sheep" pluralForm] isEqualToString:@"Sheep"]);
assert([[[CWInflector inflector] singularFormOf:@"Cats"] isEqualToString:@"Cat"]);
assert([[[CWInflector inflector] singularFormOf:@"buses"] isEqualToString:@"bus"]);
assert([[[CWInflector inflector] singularFormOf:@"men"] isEqualToString:@"man"]);
assert([[@"Sheep" singularForm] isEqualToString:@"Sheep"]);
assert(![[@"cactus" pluralForm] isEqualToString:@"cacti"]);
[[CWInflector inflector] addIrregular:@"cactus" plural:@"cacti"];
assert([[@"cactus" pluralForm] isEqualToString:@"cacti"]);
printf("Tests passed\n");
[pool release];
return 0;
}
#endif