ubershmekel avatar ubershmekel committed acc0292

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

Comments (0)

Files changed (3)

     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
 
 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.