Skip to content

Instantly share code, notes, and snippets.

@kenych
Created September 28, 2015 09:39
Show Gist options
  • Save kenych/aa9516d9f9c9dd8fc5ad to your computer and use it in GitHub Desktop.
Save kenych/aa9516d9f9c9dd8fc5ad to your computer and use it in GitHub Desktop.
from abc import ABCMeta
import copy
import re
class Parser:
PATTERN = "(\d{2})::(\d{2}):(\d{2})"
def parse(self, time):
reg = re.search(self.PATTERN, time)
if (reg):
return Time(reg.group(1), reg.group(2), reg.group(3))
else:
raise ValueError("time: " + time + " doesn't match to pattern: " + self.PATTERN)
class BerlinClock:
TIME_UNIT_DELIMITER = " "
def displayTime(self, input):
t = Parser().parse(input)
return Seconds().display(t.s) + self.TIME_UNIT_DELIMITER + \
Hours().display(t.h) + self.TIME_UNIT_DELIMITER + \
Minutes().display(t.m);
class Precondition:
def __init__(self, unitsPredicate, errorMessage):
self.unitsPredicate = unitsPredicate
self.errorMessage = errorMessage
def validate(self, units):
if self.unitsPredicate(units) is False:
raise ValueError(self.errorMessage)
class Time:
def __init__(self, h, m, s):
self.h = int(h)
self.m = int(m)
self.s = int(s)
self.TIME_TO_STRING_SEPARATOR = ":"
def __str__(self):
return str(self.h) + self.TIME_TO_STRING_SEPARATOR + str(self.m) + self.TIME_TO_STRING_SEPARATOR + str(
self.s)
def __eq__(self, other):
return self.__dict__ == other.__dict__
class Color:
YELLOW = "Y"
RED = "R"
class Lamp:
def __init__(self, color):
self.switch = False
self.color = color
self.SWITCH_OFF_COLOR = "O"
def switchOn(self):
self.switch = True
def switchOff(self):
self.switch = False
def __str__(self):
return self.color.__str__() if self.switch else self.SWITCH_OFF_COLOR
class AbsTimeUnit:
__metaclass__ = ABCMeta
def display(self, units):
self.precondition.validate(units)
return " ".join(timeUnit.display(units) for timeUnit in self.timeUnits)
class Hours(AbsTimeUnit):
def __init__(self):
self.precondition = Precondition(lambda units: (units >= 1 and units <= 24),
"Hour units must be in range: units >= 1 && units <= 24")
self.timeUnits = HoursFactory().createParts()
class Minutes(AbsTimeUnit):
def __init__(self):
self.precondition = Precondition(lambda units: (units >= 0 and units <= 59),
"Minute units must be in range: units >= 0 && units <= 59")
self.timeUnits = MinutesFactory().createParts()
class Seconds(AbsTimeUnit):
def __init__(self):
self.precondition = Precondition(lambda units: (units >= 0 and units <= 59),
"Second units must be in range: units >= 0 && units <= 59")
self.timeUnits = SecondsFactory().createParts()
class TimeUnitPart:
def __init__(self, lampsFunction, lampsList):
self.lampsFunction = lampsFunction
self.lampsList = lampsList
def display(self, units):
listClone = copy.deepcopy(self.lampsList)
for i in range(0, self.lampsFunction(units)):
listClone[i].switchOn()
return "".join(str(lamp) for lamp in listClone)
def calc(self, units):
return self.lampsFunction(units)
class SecondsFactory:
def createPart(self):
return TimeUnitPart(lambda units: (abs((units % 2) - 1)), [Lamp(Color.YELLOW)])
def createParts(self):
return [self.createPart()]
class MinutesFactory:
def createTopPart(self):
return TimeUnitPart(lambda units: (units / 5),
[
Lamp(Color.YELLOW), Lamp(Color.YELLOW), Lamp(Color.RED),
Lamp(Color.YELLOW), Lamp(Color.YELLOW), Lamp(Color.RED),
Lamp(Color.YELLOW), Lamp(Color.YELLOW), Lamp(Color.RED),
Lamp(Color.YELLOW), Lamp(Color.YELLOW)
])
def createBottomPart(self):
return TimeUnitPart(lambda units: (units % 5),
[
Lamp(Color.YELLOW), Lamp(Color.YELLOW), Lamp(Color.YELLOW), Lamp(Color.YELLOW)
])
def createParts(self):
return [self.createTopPart(), self.createBottomPart()]
class HoursFactory:
def createTopPart(self):
return TimeUnitPart(lambda units: (units / 5),
[
Lamp(Color.RED), Lamp(Color.RED), Lamp(Color.RED), Lamp(Color.RED)
])
def createBottomPart(self):
return TimeUnitPart(lambda units: (units % 5),
[
Lamp(Color.RED), Lamp(Color.RED), Lamp(Color.RED), Lamp(Color.RED)
])
def createParts(self):
return [self.createTopPart(), self.createBottomPart()]
import unittest
from BerlinClock import TimeUnitPart, Hours, Minutes, Seconds, Precondition, Parser, Time, BerlinClock, Lamp, Color
class TestTimeUnits(unittest.TestCase):
def test_calc(self):
t = TimeUnitPart(lambda units: (abs((units % 2) - 1)), [Lamp(Color.YELLOW)])
self.assertEqual(t.calc(0), 1)
self.assertEqual(t.calc(20), 1)
self.assertEqual(t.calc(21), 0)
self.assertEqual(t.display(21), "O")
def test_display_minutes(self):
m = Minutes()
self.assertEquals(m.display(10), "YYOOOOOOOOO OOOO")
self.assertEquals(m.display(59), "YYRYYRYYRYY YYYY")
self.assertEquals(m.display(04), "OOOOOOOOOOO YYYY")
def test_display_hours(self):
h = Hours()
self.assertEquals(h.display(24), "RRRR RRRR")
self.assertEquals(h.display(04), "OOOO RRRR")
self.assertEquals(h.display(06), "ROOO ROOO")
def test_display_seconds(self):
s = Seconds()
self.assertEquals(s.display(20), "Y")
self.assertEquals(s.display(21), "O")
class TestParser(unittest.TestCase):
def test_parse(self):
time = Parser().parse("01::17:02")
self.assertTrue(time == Time(1, 17, 02))
def test_parse_exception(self):
with self.assertRaises(ValueError):
Parser().parse("z::17:02")
def test_berlin_clock(self):
self.assertEquals(BerlinClock().displayTime("13::17:01"), "O RROO RRRO YYROOOOOOOO YYOO")
self.assertEquals(BerlinClock().displayTime("23::59:59"), "O RRRR RRRO YYRYYRYYRYY YYYY")
self.assertEquals(BerlinClock().displayTime("16::16:16"), "Y RRRO ROOO YYROOOOOOOO YOOO")
class TestTime(unittest.TestCase):
def test_init_time(self):
t = Time(1, 2, 3)
self.assertEqual(t.h, 1)
self.assertEqual(t.m, 2)
self.assertEqual(t.s, 3)
self.assertEqual(t.__str__(), "1:2:3")
class TestColor(unittest.TestCase):
def test_color(self):
c1 = Color.RED
c2 = Color.YELLOW
self.assertEqual(c1.__str__(), "R")
self.assertEqual(c2.__str__(), "Y")
class TestLamp(unittest.TestCase):
def test_lamp(self):
l = Lamp(Color.YELLOW)
self.assertEqual(l.__str__(), "O")
l.switchOn()
self.assertEqual(l.__str__(), "Y")
def test_precondition(self):
with self.assertRaises(ValueError):
Precondition(lambda units: (units >= 1 and units <= 24),
"Hour units must be in range: units >= 1 && units <= 24").validate(444)
if __name__ == '__main__':
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment