<s> from __future__ import unicode_literals <EOL> import os <EOL> import re <EOL> from io import StringIO <EOL> class Tokens ( object ) : <EOL> TEXT = <NUM_LIT:1> <EOL> GROUP = <NUM_LIT:2> <EOL> INDENT = <NUM_LIT:4> <EOL> NEWLINE = <NUM_LIT:8> <EOL> class Indent ( object ) : <EOL> SPACE = <NUM_LIT:1> <EOL> TAB = <NUM_LIT:2> <EOL> def __init__ ( self , type , size ) : <EOL> self . type = type <EOL> self . size = size <EOL> def render ( self ) : <EOL> if self . type == Indent . SPACE : <EOL> return '<STR_LIT:U+0020>' * self . size <EOL> elif self . type == Indent . TAB : <EOL> return '<STR_LIT:\t>' * self . size <EOL> raise RuntimeError ( "<STR_LIT>" % self . type ) <EOL> def __hash__ ( self ) : <EOL> return ( self . type , self . size ) . __hash__ ( ) <EOL> def __eq__ ( self , other ) : <EOL> return hash ( self ) == hash ( other ) <EOL> def __str__ ( self ) : <EOL> return self . render ( ) ; <EOL> @ classmethod <EOL> def detect ( self , text ) : <EOL> match = re . compile ( r'<STR_LIT>' ) . match ( text ) <EOL> if match : <EOL> return Indent ( Indent . SPACE , len ( match . groups ( ) [ <NUM_LIT:0> ] ) ) <EOL> match = re . compile ( r'<STR_LIT>' ) . match ( text ) <EOL> if match : <EOL> return Indent ( Indent . TAB , len ( match . groups ( ) [ <NUM_LIT:0> ] ) ) <EOL> return None <EOL> class GherkinParser ( object ) : <EOL> def __init__ ( self , gherkin_text ) : <EOL> self . _gherkin_text = StringIO ( gherkin_text ) <EOL> self . _tokens = [ ] <EOL> self . _group = [ ] <EOL> self . _group_indent = None <EOL> def parse ( self ) : <EOL> example_re = re . compile ( r'<STR_LIT>' ) <EOL> for line in self . _gherkin_text . readlines ( ) : <EOL> if example_re . match ( line ) : <EOL> self . _collect_group_item ( line ) <EOL> else : <EOL> self . _store_and_reset_group ( ) <EOL> line = self . _strip_and_store_indent ( line ) <EOL> self . _add_text_token ( line ) <EOL> self . _finish ( ) <EOL> return self . _tokens <EOL> def _collect_group_item ( self , line ) : <EOL> if len ( self . _group ) == <NUM_LIT:0> : <EOL> indent = Indent . detect ( line ) <EOL> if indent : <EOL> self . _group_indent = indent <EOL> elements = [ item . strip ( ) for item in line . split ( '<STR_LIT:|>' ) [ <NUM_LIT:1> : - <NUM_LIT:1> ] ] <EOL> self . _group . append ( elements ) <EOL> def _store_and_reset_group ( self ) : <EOL> if len ( self . _group ) > <NUM_LIT:0> : <EOL> self . _append_token ( Tokens . GROUP , self . _group , { '<STR_LIT>' : self . _group_indent } ) <EOL> self . _group = [ ] <EOL> self . _group_indent = None <EOL> def _strip_and_store_indent ( self , line ) : <EOL> indent = Indent . detect ( line ) <EOL> if indent : <EOL> self . _append_token ( Tokens . INDENT , indent ) <EOL> return line . lstrip ( ) <EOL> return line <EOL> def _add_text_token ( self , text ) : <EOL> if len ( text ) : <EOL> self . _append_token ( Tokens . TEXT , text . rstrip ( ) ) <EOL> self . _append_token ( Tokens . NEWLINE , '<STR_LIT:\n>' ) <EOL> def _append_token ( self , type , data , meta = None ) : <EOL> self . _tokens . append ( ( type , data , meta or { } ) ) <EOL> def _finish ( self ) : <EOL> self . _store_and_reset_group ( ) <EOL> class GherkinFormatter ( object ) : <EOL> def __init__ ( self ) : <EOL> self . _result = StringIO ( ) <EOL> def format ( self , parsed ) : <EOL> for token_type , token , meta_data in parsed : <EOL> if token_type in [ Tokens . TEXT , Tokens . INDENT , Tokens . NEWLINE ] : <EOL> self . _emit ( token ) <EOL> elif token_type == Tokens . GROUP : <EOL> self . _format_group ( token , meta_data [ '<STR_LIT>' ] ) <EOL> else : <EOL> raise Exception ( '<STR_LIT>' % token_type ) <EOL> result = self . _result . getvalue ( ) <EOL> self . _result . close ( ) <EOL> return result <EOL> def _format_group ( self , group , indent ) : <EOL> widths = self . _determine_column_widths ( group ) <EOL> for line in group : <EOL> buf = StringIO ( ) <EOL> buf . write ( self . _rendered_text_object ( indent ) or '<STR_LIT>' ) <EOL> buf . write ( '<STR_LIT:|>' ) <EOL> for idx , col in enumerate ( line ) : <EOL> width = widths [ idx ] <EOL> padding = width - len ( col ) <EOL> buf . write ( '<STR_LIT:U+0020>' ) <EOL> buf . write ( col ) <EOL> buf . write ( '<STR_LIT:U+0020>' * padding ) <EOL> buf . write ( '<STR_LIT>' ) <EOL> buf . write ( '<STR_LIT:\n>' ) <EOL> self . _emit ( buf . getvalue ( ) ) <EOL> buf . close ( ) <EOL> def _determine_column_widths ( self , group ) : <EOL> widths = [ ] <EOL> for i in range ( len ( group [ <NUM_LIT:0> ] ) ) : <EOL> width = <NUM_LIT:0> <EOL> for j in range ( len ( group ) ) : <EOL> width = max ( len ( group [ j ] [ i ] ) , width ) <EOL> widths . append ( width ) <EOL> return widths <EOL> def _emit ( self , text ) : <EOL> self . _result . write ( self . _rendered_text_object ( text ) ) <EOL> def _rendered_text_object ( self , text ) : <EOL> return text . render ( ) if hasattr ( text , '<STR_LIT>' ) else text </s>
