From 9f45d5b5d399abaed4af913efa1aee61013334fc Mon Sep 17 00:00:00 2001 From: achmizs Date: Sat, 16 Jan 2016 19:11:20 -0500 Subject: [PATCH] Correct output bug and remove extraneous files --- SA_DiceBot.h | 183 --------------------------------------------- SA_DiceBot.m | 144 ----------------------------------- SA_DiceFormatter.m | 4 +- 3 files changed, 2 insertions(+), 329 deletions(-) delete mode 100644 SA_DiceBot.h delete mode 100644 SA_DiceBot.m diff --git a/SA_DiceBot.h b/SA_DiceBot.h deleted file mode 100644 index ee52bc3..0000000 --- a/SA_DiceBot.h +++ /dev/null @@ -1,183 +0,0 @@ -// -// SA_DiceBot.h -// -// Copyright (c) 2016 Said Achmiz. -// -// This software is licensed under the MIT license. -// See the file "LICENSE" for more information. -/* - The SA_DiceBot class hierarchy works like this: - - SA_DiceBot is the root class. A user of the SA_DiceBot package usually only - needs to create and manage objects of this class. An SA_DiceBot creates and - manages all other objects and classes in the package (directly or through its - other members), as needed. - - An SA_DiceBot owns a single SA_DiceRoller and a single SA_DiceFormatter. - - The objects owned by an SA_DiceBot are for the SA_DiceBot's internal use - only, and not accessible to users of the package. (But see SA_DiceRoller.h - and SA_DiceFormatter.h for information on standalone use.) - - An SA_DiceRoller owns an SA_DiceParser and an SA_DiceEvaluator. An - SA_DiceEvaluator owns an SA_DiceBag. (See Figure 1, below.) - - *--------------------------------------------------------------------------* - | Fig. 1. SA_DiceBot class hierarchy diagram. | - | | - | | - | SA_DiceBot | - | / \ | - | SA_DiceFormatter SA_DiceRoller | - | / \ | - | SA_DiceParser SA_DiceEvaluator | - | | | - | SA_DiceBag | - | | - *--------------------------------------------------------------------------* - - When the SA_DiceBot receives a recognized command that involves rolling some - dice or otherwise evaluating some sort of string of semantically meaningful - text (like just adding some numbers), it extracts that string (which may - optionally include some text label) from the rest of the message body, and - passes it to the SA_DiceRoller. - - The SA_DiceRoller strips off the label (if any), and passes the 'pure' string - to the SA_DiceParser. - - The SA_DiceParser parses the string and produces an 'expression tree' - representation of the string. An expression tree is an NSDictionary with a - certain structure (which is described in SA_DiceExpressionStringConstants.h). - - The SA_DiceRoller then passes the expression tree to the SA_DiceEvaluator. - The evaluator recursively traverses the expression tree in a depth-first - manner, computing the results of each subtree, and storing those results in - (a mutable copy of) the expression tree itself. Once the entire tree has been - evaluated, (a mutable copy of) it is returned to the SA_DiceRoller. The - SA_DiceRoller reattaches the stripped-off label (inserting it into the top - level of the expresion tree) and returns the evaluated expression tree - (now called a result) to the SA_DiceBot. - - The SA_DiceBot passes the evaluated result tree to its SA_DiceFormatter. - The formatter traverses the tree, constructing a human-readable string form of - the results, with whatever formatting it (the formatter) has been configured - to provide. The formatter then returns this formatted result string to the - SA_DiceBot. - - The SA_DiceBot then incorporates the formatted result string into some - appropriate reply message or messages, and sends the reply(ies) back to its - delegate, for transmission to the appropriate endpoint. - */ - -#import -#import "SA_Bot.h" - -@class SA_CommandResponder; - -/* - ###################################### - #### SA_DiceBot Usage Information #### - ###################################### - - I. SUPPORTED COMMANDS & PARSER MODES - - The set of commands, and the syntax and behavior of those commands, that an - SA_DiceBot supports depends on its currently set parser behavior mode (and, in - some cases, also on the currently set formatter behavior mode). (Read more - about parser behavior modes in SA_DiceParser.h, and about formatter behavior - modes in SA_DiceFormatter.h.) - - Below is a list of available parser modes, along with the commands supported in - each mode. (See section II for a list of commands that are supported in all - parser modes.) - - NOTE: Commands are not case-sensitive; e.g., 'roll', 'ROLL', and 'rOLl' all - work equally well. - - 1. DEFAULT mode - - "Default" mode is an alias for whatever default behavior is currently set for - new SA_DiceParser instances. (The "default default" behavior for the current - implementation is "legacy".) - - 2. LEGACY mode - - "Legacy" mode (mostly) emulates DiceBot by Sabin (and Dawn by xthemage before - it). The following commands are available in legacy mode. - - 1. ROLL command. - - Takes 1 or more whitespace-delimited roll strings as parameters. The roll - command is executed once for every parameter, and each execution generates - a separate result string. One reply message is sent for each result string - (or, if the simple formatter is being used, the results may optionally be - collapsed into a single reply message). - - Each roll string may optionally be suffixed with with a (configurable) - delimiter character (such as ';'), which may be followed with an arbitrary - text label (which may not contain whitespace, however). That label may then - be included in the result string (depending on the selected formatter - behavior mode and other formatter settings). - - The body of the roll string (up to the label delimiter, if any) is simply - parsed and evaluated. - - EXAMPLES (assuming legacy formatter behavior): - - Obormot: !roll 1d20 - SA_DiceBot: 1d20 < 14 = 14 > = 14 - Obormot: .roll 2+4-5 - SA_DiceBot: 2 + 4 - 5 = 1 - Obormot: /roll 2d4 1d20+19 4d10 - SA_DiceBot: 2d4 < 3 1 = 4 > = 4 - SA_DiceBot: 1d20 < 5 = 5 > + 19 = 24 - SA_DiceBot: 4d10 < 2 2 1 2 = 7 > = 7 - Obormot: !roll 1d20+4;fort_save - SA_DiceBot: (fort_save) 1d20 < 8 = 8 > + 4 = 12 - Obormot: SA_DiceBot: 1d8+6;longsword 1d6+3;shortsword - SA_DiceBot: (longsword) 1d8 < 4 = 4 > + 6 = 10 - SA_DiceBot: (shortsword) 1d6 < 2 = 2 > + 3 = 5 - - 2. TRY command. - - Takes 1 or more whitespace-delimited roll strings. Prepends "1d20+" to each - roll string, and otherwise behaves in the same way as the ROLL command. - - 3. CHAR command. - - II. OTHER COMMANDS - - III. CONFIGURATION - */ -/****************************************/ -#pragma mark SA_DiceBot class declaration -/****************************************/ - -@interface SA_DiceBot : SA_Bot - -/************************/ -#pragma mark - Properties -/************************/ - -@property (strong) SA_CommandResponder *botCommandresponder; -@property (strong) SA_CommandResponder *legacyCommandResponder; - -@property (strong) SA_CommandResponder *currentCommandResponder; - -@property (copy) NSString *commandDesignatorCharacters; - -/****************************/ -#pragma mark - Public methods -/****************************/ - -- (void)message:(NSString *)messageBody withInfo:(NSDictionary *)messageInfo; - -/****************************/ -#pragma mark - Helper methods -/****************************/ - -- (NSArray *)repliesForCommandString:(NSString *)commandString messageInfo:(NSDictionary *)messageInfo byName:(BOOL)byName; - -- (void)loadDefaultCommandResponders; - -@end diff --git a/SA_DiceBot.m b/SA_DiceBot.m deleted file mode 100644 index 9430899..0000000 --- a/SA_DiceBot.m +++ /dev/null @@ -1,144 +0,0 @@ -// -// SA_DiceBot.m -// -// Copyright (c) 2016 Said Achmiz. -// -// This software is licensed under the MIT license. -// See the file "LICENSE" for more information. - -#import "SA_DiceBot.h" - -#import "SA_BotDelegate.h" -#import "SA_CommandResponder.h" -#import "SA_BotCommandResponder.h" -#import "SA_LegacyCommandResponder.h" -#import "SA_ErrorCatalog.h" -#import "NSString+SA_NSStringExtensions.h" -#import "NSRange-Conventional.h" - -/*********************************************/ -#pragma mark - SA_DiceBot class implementation -/*********************************************/ - -@implementation SA_DiceBot - -/**************************/ -#pragma mark - Initializers -/**************************/ - -- (instancetype)init -{ - return [self initWithName:@"DIE_BOT"]; -} - -- (instancetype)initWithName:(NSString *)name -{ - if(self = [super initWithName:name]) - { - NSLog(NSLocalizedString(@"Initializing SA_DiceBot with name \"%@\"", @"{display name of the bot}"), name); - - self.commandDesignatorCharacters = @".!/"; - - [self loadDefaultCommandResponders]; - } - return self; -} - -/****************************/ -#pragma mark - Public methods -/****************************/ - -- (void)message:(NSString *)messageBody withInfo:(NSDictionary *)messageInfo -{ - if([messageBody isEqualToString:@""]) - { - // Ignore empty messages. - } - else - { - NSRange commandRange; - BOOL byName; - - // Is the message a possible command? That is, does it start with any of - // the permitted initial characters that designate a command? - NSString *firstChar = [messageBody substringToIndex:1]; - if([self.commandDesignatorCharacters containsCharactersInString:firstChar]) - { - commandRange = NSMakeRange(1, messageBody.length - 1); - byName = NO; - } - else - { - // We also recognize commands that come after mentions of the bot's - // name at the beginning of the message. - NSRange possibleNameRange = NSRangeMake(0, self.name.length); - if(messageBody.length > self.name.length && - [[messageBody substringWithRange:possibleNameRange] isEqualToString:self.name]) - { - commandRange = [messageBody rangeToEndFrom:[messageBody firstNonWhitespaceAfterRange:[messageBody firstWhitespaceAfterRange:possibleNameRange]]]; - byName = YES; - } - else - { - // Does not begin with a command. Ignore. - return; - } - } - - // Extract the part of the string that is the actual command. - NSString *commandString = [messageBody substringWithRange:commandRange]; - - // Get the replies for this command. - NSArray *replies = [self repliesForCommandString:commandString messageInfo:messageInfo byName:byName]; - - // Send the replies. - [replies enumerateObjectsUsingBlock:^(NSDictionary *reply, NSUInteger idx, BOOL *stop) { - [self.delegate SA_botMessage:reply[SA_DB_MESSAGE_BODY] - from:self - withInfo:reply[SA_DB_MESSAGE_INFO]]; - }]; - } -} - -/****************************/ -#pragma mark - Helper methods -/****************************/ - -- (NSArray *)repliesForCommandString:(NSString *)commandString messageInfo:(NSDictionary *)messageInfo byName:(BOOL)byName -{ - NSError *error; - NSArray *replies = [self.botCommandresponder repliesForCommandString:commandString messageInfo:messageInfo error:&error]; - - if(error && error.code == SA_DiceBotErrorUnknownCommand) - { - error = nil; - replies = [self.currentCommandResponder repliesForCommandString:commandString messageInfo:messageInfo error:&error]; - } - - if(error) - { - // Is outputting the provided error the right way to do error handling - // here? I don't know. Maybe not. For now, that's what it is. - NSString *errorReply = [NSString stringWithFormat:NSLocalizedString(@"ERROR: %@ (%@ %@)", @"{description}, {failure reason}, {recovery suggestion}"), - error.localizedDescription, - error.localizedFailureReason, - error.localizedRecoverySuggestion]; - - replies = [replies arrayByAddingObject:@{ SA_DB_MESSAGE_BODY : errorReply, - SA_DB_MESSAGE_INFO : messageInfo }]; - } - - return replies; -} - -- (void)loadDefaultCommandResponders -{ - self.legacyCommandResponder = [SA_LegacyCommandResponder new]; - self.botCommandresponder = [SA_BotCommandResponder new]; - - // The default command responder, in the current implementation, is the - // legacy command responder. - self.currentCommandResponder = self.legacyCommandResponder; -} - -@end diff --git a/SA_DiceFormatter.m b/SA_DiceFormatter.m index 1e7f1f7..29b8f1f 100644 --- a/SA_DiceFormatter.m +++ b/SA_DiceFormatter.m @@ -173,7 +173,7 @@ static NSDictionary *_stringFormatRules; { [formattedString appendFormat:@" = %@", expression[SA_DB_RESULT]]; } - else if(_legacyModeErrorReportingEnabled == YES && [getErrorsForExpression(expression) count] > 1) + else if(_legacyModeErrorReportingEnabled == YES && [getErrorsForExpression(expression) count] > 0) { if([getErrorsForExpression(expression) count] == 1) { @@ -187,7 +187,7 @@ static NSDictionary *_stringFormatRules; [formattedString appendString:[SA_DiceFormatter descriptionForError:error]]; if(idx != [getErrorsForExpression(expression) count] - 1) { - [formattedString appendFormat:@", "]; + [formattedString appendFormat:@" / "]; } else {