Skip to content

Instantly share code, notes, and snippets.

@hltbra
Last active July 26, 2018 22:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hltbra/9c0983584e40bd690b36da1a37303950 to your computer and use it in GitHub Desktop.
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)
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
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
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