ソースを参照

Correct output bug and remove extraneous files

master
achmizs 10年前
コミット
9f45d5b5d3
3個のファイルの変更2行の追加329行の削除
  1. 0
    183
      SA_DiceBot.h
  2. 0
    144
      SA_DiceBot.m
  3. 2
    2
      SA_DiceFormatter.m

+ 0
- 183
SA_DiceBot.h ファイルの表示

@@ -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 <Foundation/Foundation.h>
#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 <NSDictionary *> *)repliesForCommandString:(NSString *)commandString messageInfo:(NSDictionary *)messageInfo byName:(BOOL)byName;

- (void)loadDefaultCommandResponders;

@end

+ 0
- 144
SA_DiceBot.m ファイルの表示

@@ -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 <NSDictionary *> *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 <NSDictionary *> *)repliesForCommandString:(NSString *)commandString messageInfo:(NSDictionary *)messageInfo byName:(BOOL)byName
{
NSError *error;
NSArray <NSDictionary *> *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

+ 2
- 2
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
{

読み込み中…
キャンセル
保存