2
\$\begingroup\$

Based on a python name generator grammar I found here I've decided to write my own in objective-C. The idea is I can load the grammar from a plist file and generate random names from it.

I'm looking for a general code review and any comments and or suggestions.

NameGenerator.h:

@interface NameGenerator : NSObject
- (id)initWithGrammar:(NSString *)plistName;
- (NSString*)name;
@end

NameGenerator.m:

@interface NameGenerator()
@property (nonatomic,strong) NSDictionary *grammar;
-(NSString*)replaceKey:(NSString*)input;
@end
@implementation NameGenerator
@synthesize grammar = _grammar;
- (id)init {
 @throw [NSException exceptionWithName: @"NameGeneratorInit"
 reason: @"-init is not allowed, use -initWithGrammar: instead"
 userInfo: nil];
}
- (id)initWithGrammar:(NSString *)plistName
{
 self = [super init];
 if (self) {
 NSString* plistPath = [[NSBundle mainBundle] pathForResource:plistName ofType:@"plist"];
 self.grammar = [NSDictionary dictionaryWithContentsOfFile:plistPath];
 id object = [self.grammar objectForKey:@"grammar"];
 if (![object isKindOfClass:[NSString class]]) {
 NSLog(@"initWithGrammar: Not a grammar plist");
 self = nil;
 }
 NSString *ver = object;
 if (![ver isEqualToString:@"NG.CF.1"]) {
 NSLog(@"initWithGrammar: plist version is wrong");
 self = nil;
 }
 }
 return self;
}
- (NSString*)name {
 return [self replaceKey:@"name"];
}
-(NSString*)replaceKey:(NSString*)input
{
 NSString *output = @"";
 NSArray *parts = [input componentsSeparatedByString:@","];
 if ([parts count] > 1) {
 for(NSString *part in parts) {
 output = [output stringByAppendingString:[self replaceKey:part]];
 }
 } else {
 id object = [self.grammar objectForKey:input];
 if ([object isKindOfClass:[NSString class]]) {
 output = [self replaceKey:object];
 }
 else if ([object isKindOfClass:[NSArray class]]) {
 NSUInteger randomIndex = arc4random() % [object count];
 output = [self replaceKey:[object objectAtIndex:randomIndex]];
 }
 else {
 output = input;
 }
 }
 return output;
}

ork.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
 <key>grammar</key>
 <string>NG.CF.1</string>
 <key>name</key>
 <string>nameStart,nameMiddle0to3,nameEnd</string>
 <key>nameMiddle0to3</key>
 <array>
 <string></string>
 <string>nameMiddle</string>
 <string>nameMiddle,nameMiddle</string>
 <string>nameMiddle,nameMiddle,nameMiddle</string>
 </array>
 <key>nameStart</key>
 <array>
 <string>nsCons,tick,nsCons,nmVowel</string>
 <string>nsCons,nmVowel</string>
 <string>nsCons,nmVowel</string>
 <string>nsCons,nmVowel</string>
 <string>nsVowel</string>
 </array>
 <key>nameMiddle</key>
 <string>nmCons,nmVowel</string>
 <key>nameEnd</key>
 <array>
 <string>neCons,neVowel</string>
 <string>neCons</string>
 <string>neCons</string>
 </array>
 <key>nsCons</key>
 <array>
 <string>d</string>
 <string>g</string>
 <string>k</string>
 <string>t</string>
 <string>gr</string>
 </array>
 <key>nmCons</key>
 <array>
 <string>d</string>
 <string>g</string>
 <string>k</string>
 <string>t</string>
 <string>r</string>
 <string>s</string>
 <string>z</string>
 <string>kt</string>
 <string>rs</string>
 <string>gr</string>
 </array>
 <key>neCons</key>
 <array>
 <string>r</string>
 <string>s</string>
 <string>z</string>
 </array>
 <key>nsVowel</key>
 <array>
 <string>e</string>
 <string>u</string>
 </array>
 <key>nmVowel</key>
 <array>
 <string>a</string>
 <string>e</string>
 <string>i</string>
 <string>o</string>
 <string>u</string>
 </array>
 <key>neVowel</key>
 <array>
 <string>a</string>
 <string>u</string>
 </array>
 <key>tick</key>
 <array>
 <string>&apos;</string>
 </array>
</dict>
</plist>
palacsint
30.3k9 gold badges81 silver badges157 bronze badges
asked Aug 14, 2012 at 7:59
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

It generally looks like good code to me, so these come under "nits":

  • In -initWithGrammar: you're actually passing the name of the grammar, not the grammar itself. Perhaps -initWithGrammarName: would be better.

  • It's conventional not to use accessors in initialisers or destructors, because the object isn't in a consistent state during these methods. This means replacing self.grammar = with _grammar = in the initialiser.

  • Given the change made above, why does the grammar property need to be readwrite? Customers of your class pass a filename into the initialiser and then, presumably, never change the constructed dictionary so it can be readonly.

  • in replaceKey:, if the plist happens to contain a number or a dictionary value for the key then you'll return that instead of an NSString. I realise the grammar format isn't supposed to do that but it's good form to assert this so that when it does happen, people find out the easy way.

answered Aug 14, 2012 at 12:11
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.