# metricbot

committed acc0292

Made metricbot conversion functions into a class with state to do complex
conversion which consume some of the input.

# metricbot.py

`     else:`
`         return unit.name + 's'`
` `
`-def number_unit_conversions(text):`
`-    number_word_pairs = re.findall(r'([/\d,\.]+)[ ]?([a-zA-Z\-/]+)', text)`
`-    for number, word in number_word_pairs:`
`-        if word in IMP_UNITS:`
`-            no_commas_number = number.replace(',', '')`
`+`
`+class Converter:`
`+    def __init__(self, text):`
`+        self.text = text`
`+        self.src = text`
`+`
`+    def response(self):`
`+        conversions = self.find_imperials()`
`+        response = '\n\n'.join(conversions)`
`+        return response`
`+        `
`+    def number_unit_conversions(self):`
`+        text = self.text`
`+        number_word_pairs = re.findall(r'([/\d,\.]+)[ ]?([a-zA-Z\-/]+)', text)`
`+        for number, word in number_word_pairs:`
`+            if word in IMP_UNITS:`
`+                no_commas_number = number.replace(',', '')`
`+                try:`
`+                    amount = float(no_commas_number)`
`+                except ValueError:`
`+                    # bad number eg '0.,0'`
`+                    continue`
`+                unit = IMP_UNITS[word]`
`+                si_unit = SI_UNITS[unit]`
`+                converted = (amount * unit).rescale(si_unit)`
`+                converted = float(converted)`
`+                num_str = nice_number_str(converted)`
`+                `
`+                src = '%s %s' % (number, word)`
`+                dst = '%s %s' % (num_str, nice_unit_name(si_unit))`
`+                yield src, dst`
`+`
`+    def foot_and_inch_simple(self):`
`+        text = self.text`
`+        matcher_re = r'''(\d+)\s*(?:ft|foot|feet)\.?\s+(\d+)\s*(?:in|inches|inch)[\w]*.*\$'''`
`+        for match in re.finditer(matcher_re, text):`
`+            feet, inches = match.groups()`
`+            # consume the input so it doesn't confuse with the number_unit_conversions`
`+            self.text = self.text[:match.start()] + ' ' + self.text[match.end():]`
`             try:`
`-                amount = float(no_commas_number)`
`+                yield self.foot_and_inch_yielder(feet, inches)`
`             except ValueError:`
`                 # bad number eg '0.,0'`
`                 continue`
`-            unit = IMP_UNITS[word]`
`-            si_unit = SI_UNITS[unit]`
`-            converted = (amount * unit).rescale(si_unit)`
`-            converted = float(converted)`
`-            num_str = nice_number_str(converted)`
`-            `
`-            src = '%s %s' % (number, word)`
`-            dst = '%s %s' % (num_str, nice_unit_name(si_unit))`
`-            yield src, dst`
`+        `
` `
`-def foot_inch_apostrophe_conversions(text):`
`-    for feet, inches in re.findall(r'''(\d+)'(\d+)"''', text):`
`-        try:`
`-            feet = int(feet)`
`-            inches = int(inches)`
`-            amount = quantities.ft * feet + quantities.inch * inches`
`-            result = amount.rescale(quantities.m)`
`-            result = float(result)`
`-            num_str = nice_number_str(result)`
`-            `
`-            src = '''%d'%d"''' % (feet, inches)`
`-            dst = '%s %s' % (num_str, 'meters')`
`-            `
`-            yield src, dst`
`-            `
`-        except ValueError:`
`-            # bad number eg '0.,0'`
`-            continue`
`+    def foot_and_inch_yielder(self, feet, inches):`
`+        feet = int(feet)`
`+        inches = int(inches)`
`+        amount = quantities.ft * feet + quantities.inch * inches`
`+        result = amount.rescale(quantities.m)`
`+        result = float(result)`
`+        num_str = nice_number_str(result)`
`+        `
`+        src = '''%d'%d"''' % (feet, inches)`
`+        dst = '%s %s' % (num_str, 'meters')`
`+        `
`+        return src, dst`
`+    `
`+        `
`+    def foot_inch_apostrophe_conversions(self):`
`+        text = self.text`
`+        for feet, inches in re.findall(r'''(\d+)'(\d+)"''', text):`
`+            try:`
`+                yield self.foot_and_inch_yielder(feet, inches)`
`+            except ValueError:`
`+                # bad number eg '0.,0'`
`+                continue`
`             `
` `
`-def find_imperials(text):`
`-    conversions = []`
`-    seen = set()`
`-    for src, dst in itertools.chain(number_unit_conversions(text), foot_inch_apostrophe_conversions(text)):`
`-        if dst in seen:`
`-            continue`
`-        else:`
`-            seen.add(dst)`
`-        line = '%s = %s' % (src, dst)`
`-        conversions.append(line)`
`-    `
`-    return conversions`
`+    def find_imperials(self):`
`+        text = self.text`
`+        conversions = []`
`+        seen = set()`
`+        converters = [`
`+            self.foot_and_inch_simple(),`
`+            self.number_unit_conversions(),`
`+            self.foot_inch_apostrophe_conversions(),`
`+            ]`
`+        for src, dst in itertools.chain(*converters):`
`+            if dst in seen:`
`+                continue`
`+            else:`
`+                seen.add(dst)`
`+            line = '%s = %s' % (src, dst)`
`+            conversions.append(line)`
`+        `
`+        return conversions`
` `
` `
` def metric_response(text):`
`-    conversions = find_imperials(text)`
`-    response = '\n\n'.join(conversions)`
`     if suspected_converted_already(text):`
`         return ''`
`+    `
`+    conv = Converter(text)`
`+    response = conv.response()`
`     return response`
` `
` HOUR = 60 * 60`

# redditbot.py

` `
` import reddit`
` `
`-LIMIT = 100`
`+BATCH_LIMIT = 100`
` `
` `
` `
`         r = self.r`
`         comments = []`
`         responded = 0`
`-        for comm in r.get_all_comments(limit=LIMIT, place_holder=self.comment_place_holder):`
`+        for comm in r.get_all_comments(limit=BATCH_LIMIT, place_holder=self.comment_place_holder):`
`             # next time get the rest of the comments after this one.`
`             self.comment_place_holder = comm.name`
`             `
`         r = self.r`
`         links = []`
`         responded = 0`
`-        for link in r.get_subreddit('all').get_new(limit=LIMIT, url_data={"sort": "new"}, place_holder=self.link_place_holder):`
`+        for link in r.get_subreddit('all').get_new(limit=BATCH_LIMIT, url_data={"sort": "new"}, place_holder=self.link_place_holder):`
`             self.link_place_holder = link.id`
`             print 'l',`
`             poster = link.author`

# test_metricbot.py

`-`
`+    `
` import unittest`
` import imp`
` import time`
`            '-0.1 mph': '0.1 mph = 0.16 km/h',`
`            '1 feet 1 ft 1foot': '1 feet = 0.3 meters',`
`            '''I'm 6'3" 223lbs, so I avoid a lot of confrontations''': '''223 lbs = 101.15 kilograms\n\n6\'3" = 1.91 meters''',`
`-           '20 ft and 1 meter': '',`
`+           '20 ft and 1 meter': '', # metric and imperial at same time`
`+           "Sultan Kosen stops growing: World's tallest man reaches his peak at 8ft 3in": '8\'3" = 2.51 meters',`
`            }`
`         `
`         for text, expected in pairs.items():`
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.