Last active
July 26, 2018 22:13
-
-
Save hltbra/9c0983584e40bd690b36da1a37303950 to your computer and use it in GitHub Desktop.
playing with metaprogramming to create a spreasheet-like DSL. This is an extension of a Coding Dojo performed at Yipit (https://github.com/Yipit/yipit-dojo/tree/master/2018-07-25)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from collections import defaultdict | |
class BaseCell(object): | |
def __init__(self, value): | |
self.value = value | |
def __add__(self, other): | |
if not isinstance(other, Cell): | |
other = BaseCell(other) | |
return Add(self, other) | |
def __sub__(self, other): | |
if not isinstance(other, Cell): | |
other = BaseCell(other) | |
return Sub(self, other) | |
class Add(BaseCell): | |
def __init__(self, x, y): | |
self._x = x | |
self._y = y | |
@property | |
def value(self): | |
return self._x.value + self._y.value | |
class Sub(BaseCell): | |
def __init__(self, x, y): | |
self._x = x | |
self._y = y | |
@property | |
def value(self): | |
return self._x.value - self._y.value | |
class Cell(BaseCell): | |
def __init__(self, value=''): | |
self.value = value | |
@property | |
def value(self): | |
value = self._value | |
while isinstance(value, BaseCell): | |
value = value.value | |
return value | |
@value.setter | |
def value(self, new_value): | |
if not isinstance(new_value, BaseCell): | |
new_value = BaseCell(new_value) | |
self._value = new_value | |
class Spreadsheet(object): | |
def __init__(self): | |
self._cells = defaultdict(Cell) | |
def set(self, value, axis): | |
self._cells[axis].value = value | |
def get(self, axis): | |
return self.cell(axis).value | |
def cell(self, axis): | |
return self._cells[axis] | |
def evaluate(self, axis): | |
value = self.get(axis) | |
try: | |
return float(value) | |
except (TypeError, ValueError): | |
return value |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from collections import defaultdict | |
class BaseCell(object): | |
def __init__(self, value): | |
self.value = value | |
def __add__(self, other): | |
if not isinstance(other, Cell): | |
other = BaseCell(other) | |
return BinOp(self, other, lambda x, y: x.value + y.value) | |
def __sub__(self, other): | |
if not isinstance(other, Cell): | |
other = BaseCell(other) | |
return BinOp(self, other, lambda x, y: x.value - y.value) | |
class BinOp(BaseCell): | |
def __init__(self, x, y, calculator): | |
self._x = x | |
self._y = y | |
self._calc = calculator | |
@property | |
def value(self): | |
return self._calc(self._x, self._y) | |
class Cell(BaseCell): | |
def __init__(self, value=''): | |
self.value = value | |
@property | |
def value(self): | |
value = self._value | |
while isinstance(value, BaseCell): | |
value = value.value | |
return value | |
@value.setter | |
def value(self, new_value): | |
if not isinstance(new_value, BaseCell): | |
new_value = BaseCell(new_value) | |
self._value = new_value | |
class Spreadsheet(object): | |
def __init__(self): | |
self._cells = defaultdict(Cell) | |
def set(self, value, axis): | |
self._cells[axis].value = value | |
def get(self, axis): | |
return self.cell(axis).value | |
def cell(self, axis): | |
return self._cells[axis] | |
def evaluate(self, axis): | |
value = self.get(axis) | |
try: | |
return float(value) | |
except (TypeError, ValueError): | |
return value |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from spreadsheet import Cell, Spreadsheet | |
def test_cell(): | |
cell = Cell('12') | |
assert cell.value == '12' | |
def test_sheet(): | |
spreadsheet = Spreadsheet() | |
spreadsheet.set('12', 'A1') | |
assert spreadsheet.get('A1') == '12' | |
def test_sheet_with_unset_cel(): | |
spreadsheet = Spreadsheet() | |
assert spreadsheet.get('A1') == '' | |
def test_sheet_can_evaluate_cell(): | |
spreadsheet = Spreadsheet() | |
spreadsheet.set(12.2, 'A1') | |
assert spreadsheet.evaluate('A1') == 12.2 | |
def test_sheet_can_evaluate_strings(): | |
spreadsheet = Spreadsheet() | |
spreadsheet.set('test string', 'A1') | |
assert spreadsheet.evaluate('A1') == 'test string' | |
def test_sheet_can_evaluate_formula_with_addition(): | |
spreadsheet = Spreadsheet() | |
spreadsheet.set(1 + 2, 'A1') | |
assert spreadsheet.evaluate('A1') == 3.0 | |
def test_spreadsheet_can_get_cell(): | |
spreadsheet = Spreadsheet() | |
spreadsheet.set('abc', 'A1') | |
assert spreadsheet.cell('A1').value == 'abc' | |
def test_sheet_can_store_evaluate_formulas_with_axis(): | |
spreadsheet = Spreadsheet() | |
spreadsheet.set(1, 'A1') | |
spreadsheet.set(spreadsheet.cell("A1") + 2 + 1 - 2, 'A2') | |
assert spreadsheet.evaluate('A2') == 2.0 | |
spreadsheet.set(2, 'A1') | |
assert spreadsheet.evaluate('A2') == 3.0 | |
spreadsheet.set(spreadsheet.cell("A1") + spreadsheet.cell("A2"), 'A3') | |
assert spreadsheet.evaluate('A3') == 5 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment