From 270a4d6ce91e391fa984ca2b9cf17d01eba868ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Manh=C3=A3es?= Date: Fri, 18 Feb 2011 03:04:31 -0200 Subject: [PATCH 1/3] added support to an alternate operator - div, as an option for objects that override __or__ --- .../alternate_operator_when_ror_is_overriden.txt | 9 +++++++++ should_dsl/dsl.py | 16 ++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 should_dsl/doctests/alternate_operator_when_ror_is_overriden.txt diff --git a/should_dsl/doctests/alternate_operator_when_ror_is_overriden.txt b/should_dsl/doctests/alternate_operator_when_ror_is_overriden.txt new file mode 100644 index 0000000..3c16f27 --- /dev/null +++ b/should_dsl/doctests/alternate_operator_when_ror_is_overriden.txt @@ -0,0 +1,9 @@ +>>> from should_dsl import should + +>>> class Foo: +... def __or__(self, outro): +... return True + +>>> foo = Foo() +>>> foo /should/ be(foo) + diff --git a/should_dsl/dsl.py b/should_dsl/dsl.py index aa4ad2c..8562189 100644 --- a/should_dsl/dsl.py +++ b/should_dsl/dsl.py @@ -20,11 +20,23 @@ def _evaluate(self, value): return value def __ror__(self, lvalue): + return self._left_operator_action(lvalue) + + def __rdiv__(self, lvalue): + return self._left_operator_action(lvalue) + + def _left_operator_action(self, lvalue): self._lvalue = lvalue self._create_function_matchers() return self def __or__(self, rvalue): + return self._right_operator_action(rvalue) + + def __div__(self, rvalue): + return self._right_operator_action(rvalue) + + def _right_operator_action(self, rvalue): self._destroy_function_matchers() self._rvalue = rvalue return self._check_expectation() @@ -37,7 +49,7 @@ def _check_expectation(self): def _destroy_function_matchers(self): - self._outer_frame = sys._getframe(2).f_globals + self._outer_frame = sys._getframe(3).f_globals self._remove_matchers_from_namespace() self._put_original_identifiers_back() @@ -64,7 +76,7 @@ def _put_original_identifiers_back(self): def _create_function_matchers(self): - self._outer_frame = sys._getframe(2).f_globals + self._outer_frame = sys._getframe(3).f_globals self._save_clashed_identifiers() self._put_matchers_on_namespace() From 7ede2b1234107b029887c8e1d4da750a8bc4cb61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Manh=C3=A3es?= Date: Fri, 18 Feb 2011 03:08:39 -0200 Subject: [PATCH 2/3] alternate operator works only for those objects that really need it --- ...ternate_operator_when_ror_is_overriden.txt | 31 +++++++++++++++++-- should_dsl/dsl.py | 4 +++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/should_dsl/doctests/alternate_operator_when_ror_is_overriden.txt b/should_dsl/doctests/alternate_operator_when_ror_is_overriden.txt index 3c16f27..284c14f 100644 --- a/should_dsl/doctests/alternate_operator_when_ror_is_overriden.txt +++ b/should_dsl/doctests/alternate_operator_when_ror_is_overriden.txt @@ -1,9 +1,34 @@ >>> from should_dsl import should ->>> class Foo: +>>> class Spam: ... def __or__(self, outro): ... return True ->>> foo = Foo() ->>> foo /should/ be(foo) +>>> spam = Spam() +>>> spam /should/ be(spam) + +>>> class Eggs: pass + +>>> eggs = Eggs() +>>> eggs /should/ be(eggs) +Traceback (most recent call last): + ... +TypeError: /should/ is supported only if the actual object overrides __or__, use |should| instead + +>>> "a" /should/ equal_to("a") +Traceback (most recent call last): + ... +TypeError: /should/ is supported only if the actual object overrides __or__, use |should| instead + + +>>> 1 /should/ equal_to(1) +Traceback (most recent call last): + ... +TypeError: /should/ is supported only if the actual object overrides __or__, use |should| instead + + +>>> True /should/ be(True) +Traceback (most recent call last): + ... +TypeError: /should/ is supported only if the actual object overrides __or__, use |should| instead diff --git a/should_dsl/dsl.py b/should_dsl/dsl.py index 8562189..3f10fc5 100644 --- a/should_dsl/dsl.py +++ b/should_dsl/dsl.py @@ -23,6 +23,7 @@ def __ror__(self, lvalue): return self._left_operator_action(lvalue) def __rdiv__(self, lvalue): + self._ensure_actual_object_needs_div_operator(lvalue) return self._left_operator_action(lvalue) def _left_operator_action(self, lvalue): @@ -47,6 +48,9 @@ def _check_expectation(self): self._rvalue.message_for_failed_should_not() or \ self._rvalue.message_for_failed_should()) + def _ensure_actual_object_needs_div_operator(self, actual): + if not (hasattr(actual, '__or__') and 'instance' in str(type(actual))): + raise TypeError("/should/ is supported only if the actual object overrides __or__, use |should| instead") def _destroy_function_matchers(self): self._outer_frame = sys._getframe(3).f_globals From 2f81d0253c991b9f6b17fb85c24e3429cc94c2f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Manh=C3=A3es?= Date: Fri, 18 Feb 2011 03:15:50 -0200 Subject: [PATCH 3/3] added some textual explanation to alternate operator doctests --- ...ternate_operator_when_ror_is_overriden.txt | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/should_dsl/doctests/alternate_operator_when_ror_is_overriden.txt b/should_dsl/doctests/alternate_operator_when_ror_is_overriden.txt index 284c14f..5996937 100644 --- a/should_dsl/doctests/alternate_operator_when_ror_is_overriden.txt +++ b/should_dsl/doctests/alternate_operator_when_ror_is_overriden.txt @@ -1,12 +1,27 @@ ->>> from should_dsl import should +>>> from should_dsl import should, should_not + +Objects that have an __or__ method will not work properly with standard should-dsl form, that uses __ror__ operator. For these cases, should_dsl provides an alternative form using the div operator: >>> class Spam: ... def __or__(self, outro): ... return True >>> spam = Spam() +>>> spam |should| be(spam) +Traceback (most recent call last): + ... +NameError: name 'be' is not defined + >>> spam /should/ be(spam) + +If the object having __or__ is the expected object, everything works normally. + +>>> "spam" |should_not| be(spam) + + +The alternative form can only be used if the actual object really needs it: + >>> class Eggs: pass >>> eggs = Eggs() @@ -21,7 +36,9 @@ Traceback (most recent call last): TypeError: /should/ is supported only if the actual object overrides __or__, use |should| instead ->>> 1 /should/ equal_to(1) +Built-in objects that have an __or__ method (e.g. integer numbers, True and False) but works fine with standard |should| will not accept the div form: + +>>> 1 /should/ be(1) Traceback (most recent call last): ... TypeError: /should/ is supported only if the actual object overrides __or__, use |should| instead