Command Line Subcommands in Objective-C
Here’s the translation of the Go code to Objective-C, with explanations in Markdown format suitable for Hugo:
Our first program demonstrates how to create command-line subcommands, each with its own set of flags. This is similar to how tools like git
have different subcommands (e.g., git commit
, git push
) with their own options.
#import <Foundation/Foundation.h>
@interface SubcommandParser : NSObject
@property (nonatomic, strong) NSString *subcommand;
@property (nonatomic, strong) NSMutableDictionary *flags;
- (instancetype)initWithSubcommand:(NSString *)subcommand;
- (void)addFlagWithName:(NSString *)name defaultValue:(id)defaultValue description:(NSString *)description;
- (void)parse:(NSArray *)arguments;
- (id)valueForFlag:(NSString *)flagName;
- (NSArray *)remainingArguments;
@end
@implementation SubcommandParser
- (instancetype)initWithSubcommand:(NSString *)subcommand {
self = [super init];
if (self) {
_subcommand = subcommand;
_flags = [NSMutableDictionary dictionary];
}
return self;
}
- (void)addFlagWithName:(NSString *)name defaultValue:(id)defaultValue description:(NSString *)description {
self.flags[name] = @{@"value": defaultValue, @"description": description};
}
- (void)parse:(NSArray *)arguments {
NSMutableArray *remaining = [NSMutableArray array];
for (NSString *arg in arguments) {
if ([arg hasPrefix:@"--"]) {
NSArray *components = [arg componentsSeparatedByString:@"="];
NSString *flagName = [components[0] substringFromIndex:2];
id value = components.count > 1 ? components[1] : @YES;
self.flags[flagName][@"value"] = value;
} else {
[remaining addObject:arg];
}
}
self.flags[@"remaining"] = remaining;
}
- (id)valueForFlag:(NSString *)flagName {
return self.flags[flagName][@"value"];
}
- (NSArray *)remainingArguments {
return self.flags[@"remaining"];
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSArray *args = [[NSProcessInfo processInfo] arguments];
if (args.count < 2) {
NSLog(@"expected 'foo' or 'bar' subcommands");
return 1;
}
NSString *subcommand = args[1];
if ([subcommand isEqualToString:@"foo"]) {
SubcommandParser *fooCmd = [[SubcommandParser alloc] initWithSubcommand:@"foo"];
[fooCmd addFlagWithName:@"enable" defaultValue:@NO description:@"enable"];
[fooCmd addFlagWithName:@"name" defaultValue:@"" description:@"name"];
[fooCmd parse:[args subarrayWithRange:NSMakeRange(2, args.count - 2)]];
NSLog(@"subcommand 'foo'");
NSLog(@" enable: %@", [fooCmd valueForFlag:@"enable"]);
NSLog(@" name: %@", [fooCmd valueForFlag:@"name"]);
NSLog(@" tail: %@", [fooCmd remainingArguments]);
} else if ([subcommand isEqualToString:@"bar"]) {
SubcommandParser *barCmd = [[SubcommandParser alloc] initWithSubcommand:@"bar"];
[barCmd addFlagWithName:@"level" defaultValue:@0 description:@"level"];
[barCmd parse:[args subarrayWithRange:NSMakeRange(2, args.count - 2)]];
NSLog(@"subcommand 'bar'");
NSLog(@" level: %@", [barCmd valueForFlag:@"level"]);
NSLog(@" tail: %@", [barCmd remainingArguments]);
} else {
NSLog(@"expected 'foo' or 'bar' subcommands");
return 1;
}
}
return 0;
}
To compile and run the program:
$ clang -framework Foundation command_line_subcommands.m -o command_line_subcommands
First, invoke the foo subcommand:
$ ./command_line_subcommands foo --enable --name=joe a1 a2
subcommand 'foo'
enable: 1
name: joe
tail: (
a1,
a2
)
Now try bar:
$ ./command_line_subcommands bar --level=8 a1
subcommand 'bar'
level: 8
tail: (
a1
)
But bar won’t accept foo’s flags:
$ ./command_line_subcommands bar --enable a1
subcommand 'bar'
level: 0
tail: (
"--enable",
a1
)
This example demonstrates how to implement command-line subcommands in Objective-C. We’ve created a SubcommandParser
class to handle parsing of arguments for each subcommand. The main function checks which subcommand is invoked and processes the arguments accordingly.
Note that Objective-C doesn’t have built-in support for command-line argument parsing like Go’s flag
package. In a real-world application, you might want to use a third-party library for more robust command-line argument parsing.