sopel.modules.units.distance()   F
last analyzed

Complexity

Conditions 20

Size

Total Lines 78
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 67
dl 0
loc 78
rs 0
c 0
b 0
f 0
cc 20
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like sopel.modules.units.distance() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# coding=utf-8
2
"""
3
units.py - Unit conversion module for Sopel
4
Copyright © 2013, Elad Alfassa, <[email protected]>
5
Copyright © 2013, Dimitri Molenaars, <[email protected]>
6
Licensed under the Eiffel Forum License 2.
7
8
https://sopel.chat
9
"""
10
from __future__ import unicode_literals, absolute_import, print_function, division
11
12
import re
13
14
from sopel.module import commands, example, NOLIMIT
15
16
17
find_temp = re.compile(r'(-?[0-9]*\.?[0-9]*)[ °]*(K|C|F)', re.IGNORECASE)
18
find_length = re.compile(r'([0-9]*\.?[0-9]*)[ ]*(mile[s]?|mi|inch|in|foot|feet|ft|yard[s]?|yd|(?:milli|centi|kilo|)meter[s]?|[mkc]?m|ly|light-year[s]?|au|astronomical unit[s]?|parsec[s]?|pc)', re.IGNORECASE)
19
find_mass = re.compile(r'([0-9]*\.?[0-9]*)[ ]*(lb|lbm|pound[s]?|ounce|oz|(?:kilo|)gram(?:me|)[s]?|[k]?g)', re.IGNORECASE)
20
21
22
def f_to_c(temp):
23
    return (float(temp) - 32) * 5 / 9
24
25
26
def c_to_k(temp):
27
    return temp + 273.15
28
29
30
def c_to_f(temp):
31
    return (9.0 / 5.0 * temp + 32)
32
33
34
def k_to_c(temp):
35
    return temp - 273.15
36
37
38
@commands('temp')
39
@example('.temp 100F', '37.78°C = 100.00°F = 310.93K')
40
@example('.temp 100C', '100.00°C = 212.00°F = 373.15K')
41
@example('.temp 100K', '-173.15°C = -279.67°F = 100.00K')
42
def temperature(bot, trigger):
43
    """Convert temperatures"""
44
    try:
45
        source = find_temp.match(trigger.group(2)).groups()
46
    except (AttributeError, TypeError):
47
        bot.reply("That's not a valid temperature.")
48
        return NOLIMIT
49
    unit = source[1].upper()
50
    numeric = float(source[0])
51
    celsius = 0
52
    if unit == 'C':
53
        celsius = numeric
54
    elif unit == 'F':
55
        celsius = f_to_c(numeric)
56
    elif unit == 'K':
57
        celsius = k_to_c(numeric)
58
59
    kelvin = c_to_k(celsius)
60
    fahrenheit = c_to_f(celsius)
61
62
    if kelvin >= 0:
63
        bot.reply("{:.2f}°C = {:.2f}°F = {:.2f}K".format(celsius, fahrenheit, kelvin))
64
    else:
65
        bot.reply("Physically impossible temperature.")
66
67
68
@commands('length', 'distance')
69
@example('.distance 3m', '3.00m = 9 feet, 10.11 inches')
70
@example('.distance 3km', '3.00km = 1.86 miles')
71
@example('.distance 3 miles', '4.83km = 3.00 miles')
72
@example('.distance 3 inch', '7.62cm = 3.00 inches')
73
@example('.distance 3 feet', '91.44cm = 3 feet, 0.00 inches')
74
@example('.distance 3 yards', '2.74m = 9 feet, 0.00 inches')
75
@example('.distance 155cm', '1.55m = 5 feet, 1.02 inches')
76
@example('.length 3 ly', '28382191417742.40km = 17635876112814.77 miles')
77
@example('.length 3 au', '448793612.10km = 278867421.71 miles')
78
@example('.length 3 parsec', '92570329129020.20km = 57520535754731.61 miles')
79
def distance(bot, trigger):
80
    """Convert distances"""
81
    try:
82
        source = find_length.match(trigger.group(2)).groups()
83
    except (AttributeError, TypeError):
84
        bot.reply("That's not a valid length unit.")
85
        return NOLIMIT
86
    unit = source[1].lower()
87
    numeric = float(source[0])
88
    meter = 0
89
    if unit in ("meters", "meter", "m"):
90
        meter = numeric
91
    elif unit in ("millimeters", "millimeter", "mm"):
92
        meter = numeric / 1000
93
    elif unit in ("kilometers", "kilometer", "km"):
94
        meter = numeric * 1000
95
    elif unit in ("miles", "mile", "mi"):
96
        meter = numeric / 0.00062137
97
    elif unit in ("inch", "in"):
98
        meter = numeric / 39.370
99
    elif unit in ("centimeters", "centimeter", "cm"):
100
        meter = numeric / 100
101
    elif unit in ("feet", "foot", "ft"):
102
        meter = numeric / 3.2808
103
    elif unit in ("yards", "yard", "yd"):
104
        meter = numeric / (3.2808 / 3)
105
    elif unit in ("light-year", "light-years", "ly"):
106
        meter = numeric * 9460730472580800
107
    elif unit in ("astronomical unit", "astronomical units", "au"):
108
        meter = numeric * 149597870700
109
    elif unit in ("parsec", "parsecs", "pc"):
110
        meter = numeric * 30856776376340068
111
112
    if meter >= 1000:
113
        metric_part = '{:.2f}km'.format(meter / 1000)
114
    elif meter < 0.01:
115
        metric_part = '{:.2f}mm'.format(meter * 1000)
116
    elif meter < 1:
117
        metric_part = '{:.2f}cm'.format(meter * 100)
118
    else:
119
        metric_part = '{:.2f}m'.format(meter)
120
121
    # Shit like this makes me hate being an American.
122
    inch = meter * 39.37
123
    foot = int(inch) // 12
124
    inch = inch - (foot * 12)
125
    yard = foot // 3
126
    mile = meter * 0.000621371192
127
128
    if yard > 500:
129
        stupid_part = '{:.2f} miles'.format(mile)
130
    else:
131
        parts = []
132
        if yard >= 100:
133
            parts.append('{} yards'.format(yard))
134
            foot -= (yard * 3)
135
136
        if foot == 1:
137
            parts.append('1 foot')
138
        elif foot != 0:
139
            parts.append('{:.0f} feet'.format(foot))
140
141
        parts.append('{:.2f} inches'.format(inch))
142
143
        stupid_part = ', '.join(parts)
144
145
    bot.reply('{} = {}'.format(metric_part, stupid_part))
146
147
148
@commands('weight', 'mass')
149
def mass(bot, trigger):
150
    """Convert mass"""
151
    try:
152
        source = find_mass.match(trigger.group(2)).groups()
153
    except (AttributeError, TypeError):
154
        bot.reply("That's not a valid mass unit.")
155
        return NOLIMIT
156
    unit = source[1].lower()
157
    numeric = float(source[0])
158
    metric = 0
159
    if unit in ("gram", "grams", "gramme", "grammes", "g"):
160
        metric = numeric
161
    elif unit in ("kilogram", "kilograms", "kilogramme", "kilogrammes", "kg"):
162
        metric = numeric * 1000
163
    elif unit in ("lb", "lbm", "pound", "pounds"):
164
        metric = numeric * 453.59237
165
    elif unit in ("oz", "ounce"):
166
        metric = numeric * 28.35
167
168
    if metric >= 1000:
169
        metric_part = '{:.2f}kg'.format(metric / 1000)
170
    else:
171
        metric_part = '{:.2f}g'.format(metric)
172
173
    ounce = metric * .035274
174
    pound = int(ounce) // 16
175
    ounce = ounce - (pound * 16)
176
177
    if pound > 1:
178
        stupid_part = '{} pounds'.format(pound)
179
        if ounce > 0.01:
180
            stupid_part += ' {:.2f} ounces'.format(ounce)
181
    else:
182
        stupid_part = '{:.2f} oz'.format(ounce)
183
184
    bot.reply('{} = {}'.format(metric_part, stupid_part))
185
186
187
if __name__ == "__main__":
188
    from sopel.test_tools import run_example_tests
189
    run_example_tests(__file__)
190