diff --git a/contrib_bots/bots/converter/ConverterBot/multiple-converts.png b/contrib_bots/bots/converter/assets/multiple-converts.png similarity index 100% rename from contrib_bots/bots/converter/ConverterBot/multiple-converts.png rename to contrib_bots/bots/converter/assets/multiple-converts.png diff --git a/contrib_bots/bots/converter/converter.config b/contrib_bots/bots/converter/converter.config new file mode 100644 index 0000000000..e69de29bb2 diff --git a/contrib_bots/bots/converter/converter.py b/contrib_bots/bots/converter/converter.py index eec22919e6..f14e00b328 100644 --- a/contrib_bots/bots/converter/converter.py +++ b/contrib_bots/bots/converter/converter.py @@ -1,157 +1,15 @@ # 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 -# A dictionary allowing the conversion of each unit to its base unit. -# An entry consists of the unit's name, a constant number and a constant -# factor that need to be added and multiplied to convert the unit into -# the base unit in the last parameter. -UNITS = {'bit': [0, 1, 'bit'], - 'byte': [0, 8, 'bit'], - 'cubic-centimeter': [0, 0.000001, 'cubic-meter'], - 'cubic-decimeter': [0, 0.001, 'cubic-meter'], - 'liter': [0, 0.001, 'cubic-meter'], - 'cubic-meter': [0, 1, 'cubic-meter'], - 'cubic-inch': [0, 0.000016387064, 'cubic-meter'], - 'fluid-ounce': [0, 0.000029574, 'cubic-meter'], - 'cubic-foot': [0, 0.028316846592, 'cubic-meter'], - 'cubic-yard': [0, 0.764554857984, 'cubic-meter'], - 'teaspoon': [0, 0.0000049289216, 'cubic-meter'], - 'tablespoon': [0, 0.000014787, 'cubic-meter'], - 'cup': [0, 0.00023658823648491, 'cubic-meter'], - 'gram': [0, 1, 'gram'], - 'kilogram': [0, 1000, 'gram'], - 'ton': [0, 1000000, 'gram'], - 'ounce': [0, 28.349523125, 'gram'], - 'pound': [0, 453.59237, 'gram'], - 'kelvin': [0, 1, 'kelvin'], - 'celsius': [273.15, 1, 'kelvin'], - 'fahrenheit': [255.372222, 0.555555, 'kelvin'], - 'centimeter': [0, 0.01, 'meter'], - 'decimeter': [0, 0.1, 'meter'], - 'meter': [0, 1, 'meter'], - 'kilometer': [0, 1000, 'meter'], - 'inch': [0, 0.0254, 'meter'], - 'foot': [0, 0.3048, 'meter'], - 'yard': [0, 0.9144, 'meter'], - 'mile': [0, 1609.344, 'meter'], - 'nautical-mile': [0, 1852, 'meter'], - 'square-centimeter': [0, 0.0001, 'square-meter'], - 'square-decimeter': [0, 0.01, 'square-meter'], - 'square-meter': [0, 1, 'square-meter'], - 'square-kilometer': [0, 1000000, 'square-meter'], - 'square-inch': [0, 0.00064516, 'square-meter'], - 'square-foot': [0, 0.09290304, 'square-meter'], - 'square-yard': [0, 0.83612736, 'square-meter'], - 'square-mile': [0, 2589988.110336, 'square-meter'], - 'are': [0, 100, 'square-meter'], - 'hectare': [0, 10000, 'square-meter'], - 'acre': [0, 4046.8564224, 'square-meter']} - -PREFIXES = {'atto': -18, - 'femto': -15, - 'pico': -12, - 'nano': -9, - 'micro': -6, - 'milli': -3, - 'centi': -2, - 'deci': -1, - 'deca': 1, - 'hecto': 2, - 'kilo': 3, - 'mega': 6, - 'giga': 9, - 'tera': 12, - 'peta': 15, - 'exa': 18} - -ALIASES = {'a': 'are', - 'ac': 'acre', - 'c': 'celsius', - 'cm': 'centimeter', - 'cm2': 'square-centimeter', - 'cm3': 'cubic-centimeter', - 'cm^2': 'square-centimeter', - 'cm^3': 'cubic-centimeter', - 'dm': 'decimeter', - 'dm2': 'square-decimeter', - 'dm3': 'cubic-decimeter', - 'dm^2': 'square-decimeter', - 'dm^3': 'cubic-decimeter', - 'f': 'fahrenheit', - 'fl-oz': 'fluid-ounce', - 'ft': 'foot', - 'ft2': 'square-foot', - 'ft3': 'cubic-foot', - 'ft^2': 'square-foot', - 'ft^3': 'cubic-foot', - 'g': 'gram', - 'ha': 'hectare', - 'in': 'inch', - 'in2': 'square-inch', - 'in3': 'cubic-inch', - 'in^2': 'square-inch', - 'in^3': 'cubic-inch', - 'k': 'kelvin', - 'kg': 'kilogram', - 'km': 'kilometer', - 'km2': 'square-kilometer', - 'km^2': 'square-kilometer', - 'l': 'liter', - 'lb': 'pound', - 'm': 'meter', - 'm2': 'square-meter', - 'm3': 'cubic-meter', - 'm^2': 'square-meter', - 'm^3': 'cubic-meter', - 'mi': 'mile', - 'mi2': 'square-mile', - 'mi^2': 'square-mile', - 'nmi': 'nautical-mile', - 'oz': 'ounce', - 't': 'ton', - 'tbsp': 'tablespoon', - 'tsp': 'teaspoon', - 'y': 'yard', - 'y2': 'square-yard', - 'y3': 'cubic-yard', - 'y^2': 'square-yard', - 'y^3': 'cubic-yard'} - -HELP_MESSAGE = ('Converter usage:\n' - '`@convert `\n' - 'Converts `number` in the unit to ' - 'the and prints the result\n' - '`number`: integer or floating point number, e.g. 12, 13.05, 0.002\n' - ' and are two of the following units:\n' - '* square-centimeter (cm^2, cm2), square-decimeter (dm^2, dm2), ' - 'square-meter (m^2, m2), square-kilometer (km^2, km2),' - ' square-inch (in^2, in2), square-foot (ft^2, ft2), square-yard (y^2, y2), ' - ' square-mile(mi^2, mi2), are (a), hectare (ha), acre (ac)\n' - '* bit, byte\n' - '* centimeter (cm), decimeter(dm), meter (m),' - ' kilometer (km), inch (in), foot (ft), yard (y),' - ' mile (mi), nautical-mile (nmi)\n' - '* Kelvin (K), Celsius(C), Fahrenheit (F)\n' - '* cubic-centimeter (cm^3, cm3), cubic-decimeter (dm^3, dm3), liter (l), ' - 'cubic-meter (m^3, m3), cubic-inch (in^3, in3), fluid-ounce (fl-oz), ' - 'cubic-foot (ft^3, ft3), cubic-yard (y^3, y3)\n' - '* gram (g), kilogram (kg), ton (t), ounce (oz), pound(lb)\n' - '* (metric only, U.S. and imperial units differ slightly:) teaspoon (tsp), tablespoon (tbsp), cup\n\n\n' - 'Allowed prefixes are:\n' - '* atto, pico, femto, nano, micro, milli, centi, deci\n' - '* deca, hecto, kilo, mega, giga, tera, peta, exa\n\n\n' - 'Usage examples:\n' - '* `@convert 12 celsius fahrenheit`\n' - '* `@convert 0.002 kilomile millimeter`\n' - '* `@convert 31.5 square-mile ha`\n' - '* `@convert 56 g lb`\n') - -QUICK_HELP = 'Enter `@convert help` for help on using the converter.' +import utils def is_float(value): try: @@ -201,22 +59,22 @@ class ConverterHandler(object): for convert_index in convert_indexes: if (convert_index + 1) < len(words) and words[convert_index + 1] == 'help': - results.append(HELP_MESSAGE) + results.append(utils.HELP_MESSAGE) continue if (convert_index + 3) < len(words): number = words[convert_index + 1] - unit_from = ALIASES.get(words[convert_index + 2], words[convert_index + 2]) - unit_to = ALIASES.get(words[convert_index + 3], words[convert_index + 3]) + 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. ' + QUICK_HELP) + results.append(number + ' is not a valid number. ' + utils.QUICK_HELP) continue number = float(number) number_res = copy.copy(number) - for key, exp in PREFIXES.items(): + for key, exp in utils.PREFIXES.items(): if unit_from.startswith(key): exponent += exp unit_from = unit_from[len(key):] @@ -224,13 +82,13 @@ class ConverterHandler(object): exponent -= exp unit_to = unit_to[len(key):] - uf_to_std = UNITS.get(unit_from, False) - ut_to_std = UNITS.get(unit_to, False) + 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. ' + QUICK_HELP) + 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.' + QUICK_HELP) + 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 @@ -238,7 +96,7 @@ class ConverterHandler(object): 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. ' + QUICK_HELP) + ' are not from the same category. ' + utils.QUICK_HELP) continue # perform the conversion between the units @@ -259,7 +117,7 @@ class ConverterHandler(object): words[convert_index + 3])) else: - results.append('Too few arguments given. ' + QUICK_HELP) + results.append('Too few arguments given. ' + utils.QUICK_HELP) new_content = '' for idx, result in enumerate(results, 1): diff --git a/contrib_bots/bots/converter/ConverterBot/docs.md b/contrib_bots/bots/converter/docs.md similarity index 98% rename from contrib_bots/bots/converter/ConverterBot/docs.md rename to contrib_bots/bots/converter/docs.md index 252b836256..415efc5bcb 100644 --- a/contrib_bots/bots/converter/ConverterBot/docs.md +++ b/contrib_bots/bots/converter/docs.md @@ -62,7 +62,7 @@ and print the result. ## Notes * You can use multiple `@convert` statements in a message, the response will look accordingly: -![multiple-converts](multiple-converts.png) +![multiple-converts](assets/multiple-converts.png) * Enter `@convert help` to display a quick overview of the converter's functionality. diff --git a/contrib_bots/bots/converter/tests.py b/contrib_bots/bots/converter/tests.py new file mode 100644 index 0000000000..3d0e6cad0b --- /dev/null +++ b/contrib_bots/bots/converter/tests.py @@ -0,0 +1,41 @@ +import converter + +def test(): + for cmd, expected_response in sample_conversation(): + message = {'content': cmd, 'subject': 'foo', + 'display_recipient': 'bar'} + class ClientDummy: + def __init__(self): + self.output = '' + def send_message(self, params): + self.output = params['content'] + handler = converter.ConverterHandler() + client_dummy = ClientDummy() + handler.handle_message(message, client_dummy, '') + if client_dummy.output != expected_response: + raise AssertionError(''' + cmd: %s + expected: %s + but got : %s + ''' % (cmd, expected_response, client_dummy.output)) +def sample_conversation(): + return [ + ('@convert 2 m cm', '2.0 m = 200.0 cm\n'), + ('@converter 2 m cm', ''), + ('@convert 12 celsius fahrenheit', + '12.0 celsius = 53.600054 fahrenheit\n'), + ('@convert 0.002 kilometer millimile', + '0.002 kilometer = 1.2427424 millimile\n'), + ('@convert 3 megabyte kilobit', + '3.0 megabyte = 24576.0 kilobit\n'), + (('foo @convert 120.5 g lb bar baz.\n' + 'baz bar bar @convert 22 k c lorem ipsum dolor'), + ('1. conversion: 120.5 g = 0.26565703 lb\n' + '2. conversion: 22.0 k = -251.15 c\n')), + ('@convert foo bar', + ('Too few arguments given. Enter `@convert help` ' + 'for help on using the converter.\n')), + ] + +if __name__ == '__main__': + test() diff --git a/contrib_bots/bots/converter/utils.py b/contrib_bots/bots/converter/utils.py new file mode 100644 index 0000000000..aa2a2a93cd --- /dev/null +++ b/contrib_bots/bots/converter/utils.py @@ -0,0 +1,146 @@ +# A dictionary allowing the conversion of each unit to its base unit. +# An entry consists of the unit's name, a constant number and a constant +# factor that need to be added and multiplied to convert the unit into +# the base unit in the last parameter. +UNITS = {'bit': [0, 1, 'bit'], + 'byte': [0, 8, 'bit'], + 'cubic-centimeter': [0, 0.000001, 'cubic-meter'], + 'cubic-decimeter': [0, 0.001, 'cubic-meter'], + 'liter': [0, 0.001, 'cubic-meter'], + 'cubic-meter': [0, 1, 'cubic-meter'], + 'cubic-inch': [0, 0.000016387064, 'cubic-meter'], + 'fluid-ounce': [0, 0.000029574, 'cubic-meter'], + 'cubic-foot': [0, 0.028316846592, 'cubic-meter'], + 'cubic-yard': [0, 0.764554857984, 'cubic-meter'], + 'teaspoon': [0, 0.0000049289216, 'cubic-meter'], + 'tablespoon': [0, 0.000014787, 'cubic-meter'], + 'cup': [0, 0.00023658823648491, 'cubic-meter'], + 'gram': [0, 1, 'gram'], + 'kilogram': [0, 1000, 'gram'], + 'ton': [0, 1000000, 'gram'], + 'ounce': [0, 28.349523125, 'gram'], + 'pound': [0, 453.59237, 'gram'], + 'kelvin': [0, 1, 'kelvin'], + 'celsius': [273.15, 1, 'kelvin'], + 'fahrenheit': [255.372222, 0.555555, 'kelvin'], + 'centimeter': [0, 0.01, 'meter'], + 'decimeter': [0, 0.1, 'meter'], + 'meter': [0, 1, 'meter'], + 'kilometer': [0, 1000, 'meter'], + 'inch': [0, 0.0254, 'meter'], + 'foot': [0, 0.3048, 'meter'], + 'yard': [0, 0.9144, 'meter'], + 'mile': [0, 1609.344, 'meter'], + 'nautical-mile': [0, 1852, 'meter'], + 'square-centimeter': [0, 0.0001, 'square-meter'], + 'square-decimeter': [0, 0.01, 'square-meter'], + 'square-meter': [0, 1, 'square-meter'], + 'square-kilometer': [0, 1000000, 'square-meter'], + 'square-inch': [0, 0.00064516, 'square-meter'], + 'square-foot': [0, 0.09290304, 'square-meter'], + 'square-yard': [0, 0.83612736, 'square-meter'], + 'square-mile': [0, 2589988.110336, 'square-meter'], + 'are': [0, 100, 'square-meter'], + 'hectare': [0, 10000, 'square-meter'], + 'acre': [0, 4046.8564224, 'square-meter']} + +PREFIXES = {'atto': -18, + 'femto': -15, + 'pico': -12, + 'nano': -9, + 'micro': -6, + 'milli': -3, + 'centi': -2, + 'deci': -1, + 'deca': 1, + 'hecto': 2, + 'kilo': 3, + 'mega': 6, + 'giga': 9, + 'tera': 12, + 'peta': 15, + 'exa': 18} + +ALIASES = {'a': 'are', + 'ac': 'acre', + 'c': 'celsius', + 'cm': 'centimeter', + 'cm2': 'square-centimeter', + 'cm3': 'cubic-centimeter', + 'cm^2': 'square-centimeter', + 'cm^3': 'cubic-centimeter', + 'dm': 'decimeter', + 'dm2': 'square-decimeter', + 'dm3': 'cubic-decimeter', + 'dm^2': 'square-decimeter', + 'dm^3': 'cubic-decimeter', + 'f': 'fahrenheit', + 'fl-oz': 'fluid-ounce', + 'ft': 'foot', + 'ft2': 'square-foot', + 'ft3': 'cubic-foot', + 'ft^2': 'square-foot', + 'ft^3': 'cubic-foot', + 'g': 'gram', + 'ha': 'hectare', + 'in': 'inch', + 'in2': 'square-inch', + 'in3': 'cubic-inch', + 'in^2': 'square-inch', + 'in^3': 'cubic-inch', + 'k': 'kelvin', + 'kg': 'kilogram', + 'km': 'kilometer', + 'km2': 'square-kilometer', + 'km^2': 'square-kilometer', + 'l': 'liter', + 'lb': 'pound', + 'm': 'meter', + 'm2': 'square-meter', + 'm3': 'cubic-meter', + 'm^2': 'square-meter', + 'm^3': 'cubic-meter', + 'mi': 'mile', + 'mi2': 'square-mile', + 'mi^2': 'square-mile', + 'nmi': 'nautical-mile', + 'oz': 'ounce', + 't': 'ton', + 'tbsp': 'tablespoon', + 'tsp': 'teaspoon', + 'y': 'yard', + 'y2': 'square-yard', + 'y3': 'cubic-yard', + 'y^2': 'square-yard', + 'y^3': 'cubic-yard'} + +HELP_MESSAGE = ('Converter usage:\n' + '`@convert `\n' + 'Converts `number` in the unit to ' + 'the and prints the result\n' + '`number`: integer or floating point number, e.g. 12, 13.05, 0.002\n' + ' and are two of the following units:\n' + '* square-centimeter (cm^2, cm2), square-decimeter (dm^2, dm2), ' + 'square-meter (m^2, m2), square-kilometer (km^2, km2),' + ' square-inch (in^2, in2), square-foot (ft^2, ft2), square-yard (y^2, y2), ' + ' square-mile(mi^2, mi2), are (a), hectare (ha), acre (ac)\n' + '* bit, byte\n' + '* centimeter (cm), decimeter(dm), meter (m),' + ' kilometer (km), inch (in), foot (ft), yard (y),' + ' mile (mi), nautical-mile (nmi)\n' + '* Kelvin (K), Celsius(C), Fahrenheit (F)\n' + '* cubic-centimeter (cm^3, cm3), cubic-decimeter (dm^3, dm3), liter (l), ' + 'cubic-meter (m^3, m3), cubic-inch (in^3, in3), fluid-ounce (fl-oz), ' + 'cubic-foot (ft^3, ft3), cubic-yard (y^3, y3)\n' + '* gram (g), kilogram (kg), ton (t), ounce (oz), pound(lb)\n' + '* (metric only, U.S. and imperial units differ slightly:) teaspoon (tsp), tablespoon (tbsp), cup\n\n\n' + 'Allowed prefixes are:\n' + '* atto, pico, femto, nano, micro, milli, centi, deci\n' + '* deca, hecto, kilo, mega, giga, tera, peta, exa\n\n\n' + 'Usage examples:\n' + '* `@convert 12 celsius fahrenheit`\n' + '* `@convert 0.002 kilomile millimeter`\n' + '* `@convert 31.5 square-mile ha`\n' + '* `@convert 56 g lb`\n') + +QUICK_HELP = 'Enter `@convert help` for help on using the converter.' diff --git a/tools/lint-all b/tools/lint-all index 95e2eb91df..1bdaf16b82 100755 --- a/tools/lint-all +++ b/tools/lint-all @@ -457,7 +457,7 @@ def build_custom_checkers(by_lang): failed = True markdown_docs_length_exclude = { - "contrib_bots/bots/converter/ConverterBot/docs.md", + "contrib_bots/bots/converter/docs.md", "docs/bots-guide.md", "docs/dev-env-first-time-contributors.md", "docs/integration-guide.md",