.. todo:: Rewrite this tutorial to explain step-by-step how to develop an small yet real project with Booleano.
Convertible parsing is when the boolean expressions should be converted into something else, most likely another filter.
For this you need a :class:`grammar <booleano.parser.Grammar>`, passed to a :class:`convertible parse manager <booleano.parser.ConvertibleParseManager>` and finally, your :class:`converter class <booleano.operations.converters.BaseConverter>`.
We're going to use the grammar with the default tokens, except for the "belongs to" and "is sub-set of" operators (the default tokens are "∈" and "⊂", respectively, which is not easy to type in a keyboard):
from booleano.parser import Grammar grammar = Grammar(belongs_to="in", is_subset="is subset of")
With this grammar
, we can write expressions like:
"thursday" in {"monday", "tuesday", "wednesday", "thursday", "friday"}
"thursday" in week_days
{"thursday", "monday"} is subset of {"monday", "tuesday", "wednesday", "thursday", "friday"}
{"thursday", "monday"} is subset of week_days
This is easy. You just need the grammar we created before:
from booleano.parser import ConvertibleParseManager parse_manager = ConvertibleParseManager(grammar)
You have to subclass :class:`booleano.operations.converters.BaseConverter` and define its abstract methods (i.e., the node-specific converters) so they return the data type you want.
That's all you need. Your module should look like this:
from booleano.parser import Grammar, ConvertibleParseManager from your_project import YourCustomConverter grammar = Grammar(belongs_to="in", is_subset="is subset of") parse_manager = ConvertibleParseManager(grammar) converter = YourCustomConverter()
It's now time to put out parser to the test! Let's start by checking how expressions are parsed:
>>> parse_manager.parse('"thursday" in {"monday", "tuesday", "wednesday", "thursday", "friday"}') <Parse tree (convertible) <BelongsTo <Set <String "monday">, <String "tuesday">, <String "friday">, <String "thursday">, <String "wednesday">> <String "thursday">>> >>> parse_manager.parse('today == "2009-07-17"') <Parse tree (convertible) <Equal <Placeholder variable "today"> <String "2009-07-17">>> >>> parse_manager.parse('today != "2009-07-17"') <Parse tree (convertible) <NotEqual <Placeholder variable "today"> <String "2009-07-17">>> >>> parse_manager.parse('~ today == "2009-07-17"') <Parse tree (convertible) <Not <Equal <Placeholder variable "today"> <String "2009-07-17">>>> >>> parse_manager.parse('today > "2009-07-17"') <Parse tree (convertible) <GreaterThan <Placeholder variable "today"> <String "2009-07-17">>> >>> parse_manager.parse('time:today == "sunday" & ~weather:will_it_rain_today("paris")') <Parse tree (convertible) <And <Equal <Placeholder variable "today" at namespace="time"> <String "sunday">> <Not <Placeholder function call "will_it_rain_today"(<String "paris">) at namespace="weather">>>>
OK, it seems like all the expressions above were parsed as expected.
In order to convert these trees with YourCustomConverter
, you'd just need
to pass its instance converter
to the parse tree (which is a callable).
For example:
>>> parse_tree = parse_manager.parse('today > "2009-07-17"') >>> the_conversion_result = parse_tree(converter)
And the_conversion_result
will be, well, the conversion result.