Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Initial commit of code extracted from my super-secret iPhone project

  • Loading branch information...
commit ad2c51d9b656f3ff0164b0e68cf1199131d3ca57 0 parents
Tom Ward authored May 28, 2009
29  ActiveSupportInflector.h
... ...
@@ -0,0 +1,29 @@
  1
+//
  2
+//  Inflector.h
  3
+//  TrollyDolly
  4
+//
  5
+//  Created by Tom Ward on 26/05/2009.
  6
+//  Copyright 2009 Tom Ward. All rights reserved.
  7
+//
  8
+
  9
+#import <Foundation/Foundation.h>
  10
+
  11
+
  12
+@interface ActiveSupportInflector : NSObject {
  13
+  NSMutableSet* uncountableWords;
  14
+  NSMutableArray* pluralRules;
  15
+  NSMutableArray* singularRules;
  16
+}
  17
+
  18
+- (void)addInflectionsFromFile:(NSString*)path;
  19
+- (void)addInflectionsFromDictionary:(NSDictionary*)dictionary;
  20
+
  21
+- (void)addUncountableWord:(NSString*)string;
  22
+- (void)addIrregularRuleForSingular:(NSString*)singular plural:(NSString*)plural;
  23
+- (void)addPluralRuleFor:(NSString*)rule replacement:(NSString*)replacement;
  24
+- (void)addSingularRuleFor:(NSString*)rule replacement:(NSString*)replacement;
  25
+
  26
+- (NSString*)pluralize:(NSString*)string;
  27
+- (NSString*)singularize:(NSString*)string;
  28
+
  29
+@end
130  ActiveSupportInflector.m
... ...
@@ -0,0 +1,130 @@
  1
+//
  2
+//  Inflector.m
  3
+//  TrollyDolly
  4
+//
  5
+//  Created by Tom Ward on 26/05/2009.
  6
+//  Copyright 2009 Tom Ward. All rights reserved.
  7
+//
  8
+
  9
+#import "ActiveSupportInflector.h"
  10
+#import "RegexKitLite.h"
  11
+
  12
+@interface ActiveSupportInflectorRule : NSObject
  13
+{
  14
+  NSString* rule;
  15
+  NSString* replacement;
  16
+}
  17
+
  18
+@property (retain) NSString* rule;
  19
+@property (retain) NSString* replacement;
  20
+
  21
++ (ActiveSupportInflectorRule*) rule:(NSString*)rule replacement:(NSString*)replacement;
  22
+
  23
+@end
  24
+
  25
+@implementation ActiveSupportInflectorRule
  26
+  @synthesize rule;
  27
+  @synthesize replacement;
  28
+
  29
++ (ActiveSupportInflectorRule*) rule:(NSString*)rule replacement:(NSString*)replacement {
  30
+  ActiveSupportInflectorRule* result;
  31
+  if (result = [[[super init] alloc] autorelease]) {
  32
+    [result setRule:rule];
  33
+    [result setReplacement:replacement];
  34
+  }
  35
+  return result;
  36
+}
  37
+
  38
+@end
  39
+
  40
+
  41
+@interface ActiveSupportInflector(PrivateMethods)
  42
+- (NSString*)_applyInflectorRules:(NSArray*)rules toString:(NSString*)string;
  43
+@end
  44
+
  45
+@implementation ActiveSupportInflector
  46
+
  47
+- (ActiveSupportInflector*)init {
  48
+  if (self = [super init]) {
  49
+    uncountableWords = [[NSMutableSet alloc] init];
  50
+    pluralRules = [[NSMutableArray alloc] init];
  51
+    singularRules = [[NSMutableArray alloc] init];
  52
+    [self addInflectionsFromFile:[[NSBundle bundleForClass:[self class]] pathForResource:@"ActiveSupportInflector" ofType:@"plist"]];
  53
+  } 
  54
+  return self; 
  55
+}
  56
+
  57
+- (void)addInflectionsFromFile:(NSString*)path {
  58
+  [self addInflectionsFromDictionary:[NSDictionary dictionaryWithContentsOfFile:path]];
  59
+}
  60
+
  61
+- (void)addInflectionsFromDictionary:(NSDictionary*)dictionary {
  62
+  for (NSArray* pluralRule in [dictionary objectForKey:@"pluralRules"]) {
  63
+    [self addPluralRuleFor:[pluralRule objectAtIndex:0] replacement:[pluralRule objectAtIndex:1]];
  64
+  }
  65
+  
  66
+  for (NSArray* singularRule in [dictionary objectForKey:@"singularRules"]) {
  67
+    [self addSingularRuleFor:[singularRule objectAtIndex:0] replacement:[singularRule objectAtIndex:1]];
  68
+  }
  69
+  
  70
+  for (NSArray* irregularRule in [dictionary objectForKey:@"irregularRules"]) {
  71
+    [self addIrregularRuleForSingular:[irregularRule objectAtIndex:0] plural:[irregularRule objectAtIndex:1]];
  72
+  }
  73
+  
  74
+  for (NSString* uncountableWord in [dictionary objectForKey:@"uncountableWords"]) {
  75
+    [self addUncountableWord:uncountableWord];
  76
+  }
  77
+}
  78
+
  79
+- (void)addUncountableWord:(NSString*)string {
  80
+  [uncountableWords addObject:string];
  81
+}
  82
+
  83
+- (void)addIrregularRuleForSingular:(NSString*)singular plural:(NSString*)plural {
  84
+  NSString* singularRule = [NSString stringWithFormat:@"%@$", plural];
  85
+  [self addSingularRuleFor:singularRule replacement:singular];
  86
+  
  87
+  NSString* pluralRule = [NSString stringWithFormat:@"%@$", singular];
  88
+  [self addPluralRuleFor:pluralRule replacement:plural];  
  89
+}
  90
+
  91
+- (void)addPluralRuleFor:(NSString*)rule replacement:(NSString*)replacement {
  92
+  [pluralRules insertObject:[ActiveSupportInflectorRule rule:rule replacement: replacement] atIndex:0];
  93
+}
  94
+
  95
+- (void)addSingularRuleFor:(NSString*)rule replacement:(NSString*)replacement {
  96
+  [singularRules insertObject:[ActiveSupportInflectorRule rule:rule replacement: replacement] atIndex:0];
  97
+}
  98
+
  99
+- (NSString*)pluralize:(NSString*)singular {
  100
+  return [self _applyInflectorRules:pluralRules toString:singular];
  101
+}
  102
+
  103
+- (NSString*)singularize:(NSString*)plural {
  104
+  return [self _applyInflectorRules:singularRules toString:plural];
  105
+}
  106
+
  107
+- (NSString*)_applyInflectorRules:(NSArray*)rules toString:(NSString*)string {
  108
+  if ([uncountableWords containsObject:string]) {
  109
+    return string;
  110
+  }
  111
+  else {
  112
+    for (ActiveSupportInflectorRule* rule in rules) {
  113
+      if ([string isMatchedByRegex:[rule rule]]) {
  114
+        NSLog([rule rule]);
  115
+        NSLog([rule replacement]);
  116
+        return [string stringByReplacingOccurrencesOfRegex:[rule rule] withString:[rule replacement]];
  117
+      }
  118
+    }
  119
+    return string;
  120
+  }  
  121
+}
  122
+
  123
+- (void)dealloc {
  124
+  [super dealloc];
  125
+  [uncountableWords release];
  126
+  [pluralRules release];
  127
+  [singularRules release];
  128
+}
  129
+
  130
+@end
206  ActiveSupportInflector.plist
... ...
@@ -0,0 +1,206 @@
  1
+{
  2
+	pluralRules = (
  3
+		(
  4
+			"$",
  5
+			s,
  6
+		),
  7
+		(
  8
+			"s$",
  9
+			s,
  10
+		),
  11
+		(
  12
+			"(ax|test)is$",
  13
+			"$1es",
  14
+		),
  15
+		(
  16
+			"(octop|vir)us$",
  17
+			"$1i",
  18
+		),
  19
+		(
  20
+			"(alias|status)$",
  21
+			"$1es",
  22
+		),
  23
+		(
  24
+			"(bu)s$",
  25
+			"$1ses",
  26
+		),
  27
+		(
  28
+			"(buffal|tomat)o$",
  29
+			"$1oes",
  30
+		),
  31
+		(
  32
+			"([ti])um$",
  33
+			"$1a",
  34
+		),
  35
+		(
  36
+			"sis$",
  37
+			ses,
  38
+		),
  39
+		(
  40
+			"(?:([^f])fe|([lr])f)$",
  41
+			"$1$2ves",
  42
+		),
  43
+		(
  44
+			"(hive)$",
  45
+			"$1s",
  46
+		),
  47
+		(
  48
+			"([^aeiouy]|qu)y$",
  49
+			"$1ies",
  50
+		),
  51
+		(
  52
+			"(x|ch|ss|sh)$",
  53
+			"$1es",
  54
+		),
  55
+		(
  56
+			"(matr|vert|ind)ix|ex$",
  57
+			"$1ices",
  58
+		),
  59
+		(
  60
+			"([m|l])ouse$",
  61
+			"$1ice",
  62
+		),
  63
+		(
  64
+			"^(ox)$",
  65
+			"$1en",
  66
+		),
  67
+		(
  68
+			"(quiz)$",
  69
+			"$1zes",
  70
+		),
  71
+	);
  72
+	singularRules = (
  73
+		(
  74
+			"(.)s$",
  75
+			"$1",
  76
+		),
  77
+		(
  78
+			"(n)ews$",
  79
+			"$1ews",
  80
+		),
  81
+		(
  82
+			"([ti])a$",
  83
+			"$1um",
  84
+		),
  85
+		(
  86
+			"(analy|ba|diagno|parenthe|progno|synop|the)ses$",
  87
+			"$1sis",
  88
+		),
  89
+		(
  90
+			"(^analy)ses$",
  91
+			"$1sis",
  92
+		),
  93
+		(
  94
+			"([^f])ves$",
  95
+			"$1fe",
  96
+		),
  97
+		(
  98
+			"(hive)s$",
  99
+			"$1",
  100
+		),
  101
+		(
  102
+			"(tive)s$",
  103
+			"$1",
  104
+		),
  105
+		(
  106
+			"([lr])ves$",
  107
+			"$1f",
  108
+		),
  109
+		(
  110
+			"([^aeiouy]|qu)ies$",
  111
+			"$1y",
  112
+		),
  113
+		(
  114
+			"series$",
  115
+			"series",
  116
+		),
  117
+		(
  118
+			"movies$",
  119
+			"movie",
  120
+		),
  121
+		(
  122
+			"(x|ch|ss|sh)es$",
  123
+			"$1",
  124
+		),
  125
+		(
  126
+			"([m|l])ice$",
  127
+			"$1ouse",
  128
+		),
  129
+		(
  130
+			"(bus)es$",
  131
+			"$1",
  132
+		),
  133
+		(
  134
+			"(o)es$",
  135
+			"$1",
  136
+		),
  137
+		(
  138
+			"(shoe)s$",
  139
+			"$1",
  140
+		),
  141
+		(
  142
+			"(cris|ax|test)es$",
  143
+			"$1is",
  144
+		),
  145
+		(
  146
+			"(octop|vir)i$",
  147
+			"$1us",
  148
+		),
  149
+		(
  150
+			"(alias|status)es$",
  151
+			"$1",
  152
+		),
  153
+		(
  154
+			"^(ox)en",
  155
+			"$1",
  156
+		),
  157
+		(
  158
+			"(vert|ind)ices$",
  159
+			"$1ex",
  160
+		),
  161
+		(
  162
+			"(matr)ices$",
  163
+			"$1ix",
  164
+		),
  165
+		(
  166
+			"(quiz)zes$",
  167
+			"$1",
  168
+		),
  169
+	);
  170
+	irregularRules = (
  171
+		(
  172
+			person,
  173
+			people,
  174
+		),
  175
+		(
  176
+			man,
  177
+			men,
  178
+		),
  179
+		(
  180
+			child,
  181
+			children,
  182
+		),
  183
+		(
  184
+			sex,
  185
+			sexes,
  186
+		),
  187
+		(
  188
+			move,
  189
+			moves,
  190
+		),
  191
+    ( 
  192
+      database,
  193
+      databases
  194
+    )
  195
+	);
  196
+	uncountableWords = (
  197
+		equipment,
  198
+		information,
  199
+		rice,
  200
+		money,
  201
+		species,
  202
+		series,
  203
+		fish,
  204
+		sheep,
  205
+	);
  206
+}
47  ActiveSupportInflectorTest.m
... ...
@@ -0,0 +1,47 @@
  1
+//
  2
+//  InflectorTest.m
  3
+//  TrollyDolly
  4
+//
  5
+//  Created by Tom Ward on 26/05/2009.
  6
+//  Copyright 2009 Tom Ward. All rights reserved.
  7
+//
  8
+
  9
+#import <Foundation/Foundation.h>
  10
+
  11
+#define HC_SHORTHAND
  12
+#import <hamcrest/hamcrest.h>
  13
+
  14
+#import "GTMSenTestCase.h"
  15
+#import "TrollyDollyUtil.h"
  16
+#import "ActiveSupportInflector.h"
  17
+
  18
+
  19
+@interface ActiveSupportInflectorTest : SenTestCase {
  20
+  ActiveSupportInflector* inflector;
  21
+}
  22
+
  23
+  @property (retain) ActiveSupportInflector* inflector;
  24
+@end
  25
+
  26
+@implementation ActiveSupportInflectorTest
  27
+
  28
+@synthesize inflector;
  29
+
  30
+- (void) setUp {
  31
+  [self setInflector:[[[ActiveSupportInflector alloc] init] autorelease]];
  32
+}
  33
+
  34
+- (void) testPluralizationAndSingularization {
  35
+  NSDictionary* dictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle bundleForClass:[self class]] pathForResource:@"ActiveSupportInflectorTest" ofType:@"plist"]];
  36
+  NSArray* singularAndPlural = [dictionary objectForKey:@"singularAndPlural"];
  37
+  for (NSArray* sAndP in singularAndPlural) {
  38
+    NSString* singular = [sAndP objectAtIndex:0];
  39
+    NSString* plural = [sAndP objectAtIndex:1];
  40
+    NSLog(plural);
  41
+    NSLog(singular);
  42
+    
  43
+    assertThat([inflector pluralize:singular], equalTo(plural));
  44
+    assertThat([inflector singularize:plural], equalTo(singular));
  45
+  }
  46
+} 
  47
+@end
78  ActiveSupportInflectorTest.plist
... ...
@@ -0,0 +1,78 @@
  1
+{
  2
+	singularAndPlural = (		
  3
+    ("search", "searches"),
  4
+    ("switch", "switches"),
  5
+    ("fix", "fixes"),
  6
+    ("box", "boxes"),
  7
+    ("process", "processes"),
  8
+    ("address", "addresses"),
  9
+    ("case", "cases"),
  10
+    ("stack", "stacks"),
  11
+    ("wish", "wishes"),
  12
+    ("fish", "fish"),
  13
+    ("category", "categories"),
  14
+    ("query", "queries"),
  15
+    ("ability", "abilities"),
  16
+    ("agency", "agencies"),
  17
+    ("movie", "movies"),
  18
+    ("archive", "archives"),
  19
+    ("index", "indices"),
  20
+    ("wife", "wives"),
  21
+    ("safe", "saves"),
  22
+    ("half", "halves"),
  23
+    ("move", "moves"),
  24
+    ("salesperson", "salespeople"),
  25
+    ("person", "people"),
  26
+    ("spokesman", "spokesmen"),
  27
+    ("man", "men"),
  28
+    ("woman", "women"),
  29
+    ("basis", "bases"),
  30
+    ("diagnosis", "diagnoses"),
  31
+    ("diagnosis_a", "diagnosis_as"),
  32
+    ("datum", "data"),
  33
+    ("medium", "media"),
  34
+    ("analysis", "analyses"),
  35
+    ("node_child", "node_children"),
  36
+    ("child", "children"),
  37
+    ("experience", "experiences"),
  38
+    ("day", "days"),
  39
+    ("comment", "comments"),
  40
+    ("foobar", "foobars"),
  41
+    ("newsletter", "newsletters"),
  42
+    ("old_news", "old_news"),
  43
+    ("news", "news"),
  44
+    ("series", "series"),
  45
+    ("species", "species"),
  46
+    ("quiz", "quizzes"),
  47
+    ("perspective", "perspectives"),
  48
+    ("ox", "oxen"),
  49
+    ("photo", "photos"),
  50
+    ("buffalo", "buffaloes"),
  51
+    ("tomato", "tomatoes"),
  52
+    ("dwarf", "dwarves"),
  53
+    ("elf", "elves"),
  54
+    ("information", "information"),
  55
+    ("equipment", "equipment"),
  56
+    ("bus", "buses"),
  57
+    ("status", "statuses"),
  58
+    ("status_code", "status_codes"),
  59
+    ("mouse", "mice"),
  60
+    ("louse", "lice"),
  61
+    ("house", "houses"),
  62
+    ("octopus", "octopi"),
  63
+    ("virus", "viri"),
  64
+    ("alias", "aliases"),
  65
+    ("portfolio", "portfolios"),
  66
+    ("vertex", "vertices"),
  67
+    ("matrix", "matrices"),
  68
+    ("axis", "axes"),
  69
+    ("testis", "testes"),
  70
+    ("crisis", "crises"),
  71
+    ("rice", "rice"),
  72
+    ("shoe", "shoes"),
  73
+    ("horse", "horses"),
  74
+    ("prize", "prizes"),
  75
+    ("edge", "edges"),
  76
+    ("database", "databases")
  77
+  );
  78
+}

0 notes on commit ad2c51d

Please sign in to comment.
Something went wrong with that request. Please try again.