# See readme.md for instructions on running this code. from __future__ import absolute_import from __future__ import division from past.utils import old_div import copy import importlib import sys from math import log10, floor import utils import re def is_float(value): try: float(value) return True except ValueError: return False # Rounds the number 'x' to 'digits' significant digits. # A normal 'round()' would round the number to an absolute amount of # fractional decimals, e.g. 0.00045 would become 0.0. # 'round_to()' rounds only the digits that are not 0. # 0.00045 would then become 0.0005. def round_to(x, digits): return round(x, digits-int(floor(log10(abs(x))))) class ConverterHandler(object): ''' This plugin allows users to make conversions between various units, e.g. Celsius to Fahrenheit, or kilobytes to gigabytes. It looks for messages of the format '@mention-bot ' The message '@mention-bot help' posts a short description of how to use the plugin, along with a list of all supported units. ''' def usage(self): return ''' This plugin allows users to make conversions between various units, e.g. Celsius to Fahrenheit, or kilobytes to gigabytes. It looks for messages of the format '@mention-bot ' The message '@mention-bot help' posts a short description of how to use the plugin, along with a list of all supported units. ''' def handle_message(self, message, client, state_handler): bot_response = get_bot_converter_response(message, client) if message['type'] == 'private': client.send_message(dict( type='private', to=message['sender_email'], content=bot_response, )) else: client.send_message(dict( type='stream', to=message['display_recipient'], subject=message['subject'], content=bot_response, )) def get_bot_converter_response(message, client): content = message['content'] words = content.lower().split() convert_indexes = [i for i, word in enumerate(words) if word == "@convert"] convert_indexes = [-1] + convert_indexes results = [] for convert_index in convert_indexes: if (convert_index + 1) < len(words) and words[convert_index + 1] == 'help': results.append(utils.HELP_MESSAGE) continue if (convert_index + 3) < len(words): number = words[convert_index + 1] unit_from = utils.ALIASES.get(words[convert_index + 2], words[convert_index + 2]) unit_to = utils.ALIASES.get(words[convert_index + 3], words[convert_index + 3]) exponent = 0 if not is_float(number): results.append(number + ' is not a valid number. ' + utils.QUICK_HELP) continue number = float(number) number_res = copy.copy(number) for key, exp in utils.PREFIXES.items(): if unit_from.startswith(key): exponent += exp unit_from = unit_from[len(key):] if unit_to.startswith(key): exponent -= exp unit_to = unit_to[len(key):] uf_to_std = utils.UNITS.get(unit_from, False) ut_to_std = utils.UNITS.get(unit_to, False) if uf_to_std is False: results.append(unit_from + ' is not a valid unit. ' + utils.QUICK_HELP) if ut_to_std is False: results.append(unit_to + ' is not a valid unit.' + utils.QUICK_HELP) if uf_to_std is False or ut_to_std is False: continue base_unit = uf_to_std[2] if uf_to_std[2] != ut_to_std[2]: unit_from = unit_from.capitalize() if uf_to_std[2] == 'kelvin' else unit_from results.append(unit_to.capitalize() + ' and ' + unit_from + ' are not from the same category. ' + utils.QUICK_HELP) continue # perform the conversion between the units number_res *= uf_to_std[1] number_res += uf_to_std[0] number_res -= ut_to_std[0] number_res /= ut_to_std[1] if base_unit == 'bit': number_res *= 1024 ** (old_div(exponent, float(3))) else: number_res *= 10 ** exponent number_res = round_to(number_res, 7) results.append('{} {} = {} {}'.format(number, words[convert_index + 2], number_res, words[convert_index + 3])) else: results.append('Too few arguments given. ' + utils.QUICK_HELP) new_content = '' for idx, result in enumerate(results, 1): new_content += ((str(idx) + '. conversion: ') if len(results) > 1 else '') + result + '\n' return new_content handler_class = ConverterHandler