예제 #1
0
def test_parse_django():
    parser = PegParser()

    f = parser.parse_django("include alpha.html")
    assert f.__class__.__name__ == 'Django'
    assert f.name == 'include'
    assert f.restline == 'alpha.html'

    f = parser.parse_django("include alpha.html bravo charlie.html delta=object.pk")
    assert f.__class__.__name__ == 'Django'
    assert f.name == 'include'
    assert f.restline == 'alpha.html bravo charlie.html delta=object.pk'
예제 #2
0
def test_parse_django():
    parser = PegParser()

    f = parser.parse_django("include alpha.html")
    assert f.__class__.__name__ == 'Django'
    assert f.name == 'include'
    assert f.restline == 'alpha.html'

    f = parser.parse_django(
        "include alpha.html bravo charlie.html delta=object.pk")
    assert f.__class__.__name__ == 'Django'
    assert f.name == 'include'
    assert f.restline == 'alpha.html bravo charlie.html delta=object.pk'
예제 #3
0
def test_parse_tag():
    parser = PegParser()

    f = parser.parse_tag("tag")
    assert str(f) == '''tag'''
    assert not hasattr(f, 'args')

    f = parser.parse_tag("tag()")
    assert str(f) == '''tag'''
    assert len(f.args) == 0

    f = parser.parse_tag("tag(a=alpha, b=2, c='charlie')")
    assert str(f) == '''tag'''
    assert len(f.args) == 3
    arg1 = f.args[0]
    assert arg1.key == 'a'
    assert arg1.value == 'alpha'
    arg1 = f.args[1]
    assert arg1.key == 'b'
    assert arg1.value == '2'
    arg1 = f.args[2]
    assert arg1.key == 'c'
    assert arg1.value == "'charlie'"

    f = parser.parse_tag("tag.cls1()")
    assert str(f) == '''tag.cls1'''
    assert f.classes == ['cls1']
    assert f.id is None
    assert len(f.args) == 0

    f = parser.parse_tag("tag.cls1.cls2()")
    assert str(f) == '''tag.cls1.cls2'''
    assert f.classes == ['cls1', 'cls2']
    assert f.id is None
    assert len(f.args) == 0

    f = parser.parse_tag("tag#id1()")
    assert str(f) == '''tag#id1'''
    assert f.classes == []
    assert f.id == 'id1'
    assert len(f.args) == 0

    f = parser.parse_tag("tag.cls1.cls2#id1()")
    assert str(f) == '''tag.cls1.cls2#id1'''
    assert f.classes == ['cls1', 'cls2']
    assert f.id == 'id1'
    assert len(f.args) == 0

    f = parser.parse_tag("tag 'content'")
    assert str(f) == '''tag ...'''
    assert not hasattr(f, 'args')
예제 #4
0
def test_parse_call():
    parser = PegParser()

    f = parser.parse_call("function(alpha, bravo, charlie)")
    assert f.__class__.__name__ == 'Call'
    assert f.name == 'function'
    assert f.arguments == ['alpha', 'bravo', 'charlie']

    f = parser.parse_call("function('Alpha', 1)")
    assert f.__class__.__name__ == 'Call'
    assert f.name == 'function'
    assert f.arguments == ["'Alpha'", '1']

    f = parser.parse_call("function(1, bravo=2, charlie=3)")
    assert f.__class__.__name__ == 'Call'
    assert f.name == 'function'
    assert f.arguments == ['1', ('bravo', '2'), ('charlie', '3')]
예제 #5
0
def test_parse_tag():
    parser = PegParser()

    f = parser.parse_tag("tag")
    assert str(f) == '''tag'''
    assert not hasattr(f, 'args')

    f = parser.parse_tag("tag()")
    assert str(f) == '''tag'''
    assert len(f.args) == 0

    f = parser.parse_tag("tag(a=alpha, b=2, c='charlie')")
    assert str(f) == '''tag'''
    assert len(f.args) == 3
    arg1 = f.args[0]
    assert arg1.key == 'a'
    assert arg1.value == 'alpha'
    arg1 = f.args[1]
    assert arg1.key == 'b'
    assert arg1.value == '2'
    arg1 = f.args[2]
    assert arg1.key == 'c'
    assert arg1.value == "'charlie'"

    f = parser.parse_tag("tag.cls1()")
    assert str(f) == '''tag.cls1'''
    assert f.classes == ['cls1']
    assert f.id is None
    assert len(f.args) == 0

    f = parser.parse_tag("tag.cls1.cls2()")
    assert str(f) == '''tag.cls1.cls2'''
    assert f.classes == ['cls1', 'cls2']
    assert f.id is None
    assert len(f.args) == 0

    f = parser.parse_tag("tag#id1()")
    assert str(f) == '''tag#id1'''
    assert f.classes == []
    assert f.id == 'id1'
    assert len(f.args) == 0

    f = parser.parse_tag("tag.cls1.cls2#id1()")
    assert str(f) == '''tag.cls1.cls2#id1'''
    assert f.classes == ['cls1', 'cls2']
    assert f.id == 'id1'
    assert len(f.args) == 0

    f = parser.parse_tag("tag 'content'")
    assert str(f) == '''tag ...'''
    assert not hasattr(f, 'args')
예제 #6
0
def test_parse_call():
    parser = PegParser()

    f = parser.parse_call("function(alpha, bravo, charlie)")
    assert f.__class__.__name__ == 'Call'
    assert f.name == 'function'
    assert f.arguments == ['alpha', 'bravo', 'charlie']

    f = parser.parse_call("function('Alpha', 1)")
    assert f.__class__.__name__ == 'Call'
    assert f.name == 'function'
    assert f.arguments == ["'Alpha'", '1']

    f = parser.parse_call("function(1, bravo=2, charlie=3)")
    assert f.__class__.__name__ == 'Call'
    assert f.name == 'function'
    assert f.arguments == ['1', ('bravo', '2'), ('charlie', '3')]
예제 #7
0
    def __init__(self, include_paths):
        self.HANDLERS = {
            LineToken.LINE_TYPE_ROOT: self.handle_root,
            LineToken.LINE_TYPE_COMMENT: self.handle_comment,
            LineToken.LINE_TYPE_CODE: self.handle_code,
            LineToken.LINE_TYPE_DJANGO: self.handle_django,
            LineToken.LINE_TYPE_TAG: self.handle_tag,
            LineToken.LINE_TYPE_CALL: self.handle_call,
        }
        # Code variables (for now, later it will be more complex... with IFs
        # and FORs and expand_vars...
        self.functions = {}
        self.variables = {}
        self.include_paths = include_paths

        from pypugly.peg_parser import PegParser
        self.__parser = PegParser()
예제 #8
0
def test_parse_code():
    parser = PegParser()

    f = parser.parse_code("var alpha = 'bravo'")
    assert f.__class__.__name__ == 'Assignment'
    assert f.left == 'alpha'
    assert f.right == '\'bravo\''
    assert str(f) == '''assign(alpha, 'bravo')'''

    f = parser.parse_code("for i in 10:")
    assert f.__class__.__name__ == 'ForLoop'
    assert f.var == 'i'
    assert f.iterator == '10'
    assert str(f) == '''forloop(i, 10)'''

    f = parser.parse_code("def alpha(bravo, charlie)")
    assert f.__class__.__name__ == 'Def'
    assert f.name == 'alpha'
    assert f.parameters == [('bravo', None), ('charlie', None)]
예제 #9
0
def test_parse_code():
    parser = PegParser()

    f = parser.parse_code("var alpha = 'bravo'")
    assert f.__class__.__name__ == 'Assignment'
    assert f.left == 'alpha'
    assert f.right == '\'bravo\''
    assert str(f) == '''assign(alpha, 'bravo')'''

    f = parser.parse_code("for i in 10:")
    assert f.__class__.__name__ == 'ForLoop'
    assert f.var == 'i'
    assert f.iterator == '10'
    assert str(f) == '''forloop(i, 10)'''

    f = parser.parse_code("def alpha(bravo, charlie)")
    assert f.__class__.__name__ == 'Def'
    assert f.name == 'alpha'
    assert f.parameters == [('bravo', None), ('charlie', None)]
예제 #10
0
class HtmlGenerator(object):

    def __init__(self, include_paths):
        self.HANDLERS = {
            LineToken.LINE_TYPE_ROOT: self.handle_root,
            LineToken.LINE_TYPE_COMMENT: self.handle_comment,
            LineToken.LINE_TYPE_CODE: self.handle_code,
            LineToken.LINE_TYPE_DJANGO: self.handle_django,
            LineToken.LINE_TYPE_TAG: self.handle_tag,
            LineToken.LINE_TYPE_CALL: self.handle_call,
        }
        # Code variables (for now, later it will be more complex... with IFs
        # and FORs and expand_vars...
        self.functions = {}
        self.variables = {}
        self.include_paths = include_paths

        from pypugly.peg_parser import PegParser
        self.__parser = PegParser()

    def generate(self, line_token):
        """
        Generates HTML from a line_token (tree).

        :param LineToken line_token:
        :return str:
        """
        lines = self._handle_line_token(line_token, self.variables)
        return '\n'.join(lines)

    def _handle_line_token(self, t, context):
        handler = self.HANDLERS.get(t.line_type)
        assert \
            handler is not None, \
            'No handler for token of type "{}"'.format(t.line_type)

        result = []
        try:
            result += handler(t, after=False, context=context)
            result += self._handle_children(t.children, context=context)
            result += handler(t, after=True, context=context)
        except Exception as e:
            reraise(e, 'While handling line-token {}'.format(six.text_type(t)))
        return result

    def _handle_children(self, children, context):
        result = []
        for i_child in children:
            result += self._handle_line_token(i_child, context=context)
        return result

    def handle_root(self, token, after, context):
        return []

    def handle_code(self, token, after, context):
        if after:
            return []

        code = self.__parser.parse_code(token.line)
        code_class = code.__class__.__name__

        if code_class == 'Assignment':
            self.variables[six.text_type(code.left)] = literal_eval(code.right)
        elif code_class == 'Def':
            self.functions[six.text_type(code.name)] = \
                Function(code.name, code.parameters, token.children)
            token.children = []
            return []
        elif code_class == 'Include':
            filename = self._eval(code.filename, context)
            parser = PugParser()
            input_contents = GetFileContents(self._find_file(filename))
            token_tree = parser.tokenize(input_contents)
            return self._handle_line_token(token_tree, self.variables)

        elif code_class == 'ForLoop':
            return [token.indentation + repr(code)]

        return []

    def handle_call(self, token, after, context):
        if after:
            return []

        # Parse function call...
        code = self.__parser.parse_call(token.line)

        # Obtain the associated function
        function = self.functions.get(six.text_type(code.name))
        assert function is not None

        # Prepare arguments
        arguments = function.format_arguments(code.arguments)

        # Prepare context for the function call, adding the global variables
        # and argument values
        context = self.variables
        context.update(arguments)

        # Call the function 'code'
        tokens = function.code[:]

        # Replaces the code indent with the function call indent.
        for i in tokens:
            i.indent -= 1

        return self._handle_children(tokens, context=context)

    def handle_django(self, token, after, context):

        if after:
            if not token.children:
                return []
            code = self.__parser.parse_django(token.line)
            end_tag = code.name
            end_tag = '{% end' + end_tag.strip() + ' %}'
            return [token.indentation + end_tag]
        else:
            code = self.__parser.parse_django(token.line)
            start_tag = code.name + ' ' + code.restline
            start_tag = '{% ' + start_tag.strip() + ' %}'
            return [token.indentation + start_tag]

    def handle_comment(self, token, after, context):
        if after:
            return []
        return []

    def handle_tag(self, token, after, context):

        # Parses the TAG line, extracting the id, classes, arguments and the
        # contents.
        try:
            tag = self.__parser.parse_tag(token.line)
        except Exception as e:
            reraise(e, 'While parsing tag in line %d' % token.line_no)
            raise

        result = []

        have_content = hasattr(tag, 'content') and tag.content
        have_children = len(token.children) > 0

        if have_content and have_children:
            raise RuntimeError('A tag should have contents OR children nodes.')

        if after:
            if not have_content and have_children:
                result.append(
                    token.indentation + '</{name}>'.format(
                        name=tag.name
                    )
                )
        else:
            args = getattr(tag, 'args', [])
            args = {
                i.key: self._eval(getattr(i, 'value', 'True'), context)
                for i in args
            }
            tag_text = create_tag(
                tag.name,
                args,
                klass=tag.classes,
                id_=tag.id
            )
            if have_content or have_children:
                tag_format = '<{}>'
            else:
                tag_format = '<{} />'
            line = token.indentation + tag_format.format(tag_text)

            if have_content:
                # With content, close the tag in the same line.
                end_tag = '</{}>'.format(tag.name)
                content = self._eval(tag.content, context)
                line += content + end_tag

            result.append(line)

        return result

    def _eval(self, literal, context):
        """
        Evaluates a literal.

        For now, we evaluate only text (unicode) or boolean values
        (True/False).

        :param str literal:
        :return object:
        """
        try:
            result = literal_eval(literal)
            if isinstance(result, bytes):
                result = result.decode('UTF-8')
            if isinstance(result, six.text_type):
                result = result.format(**context)
            return result
        except Exception as e:
            reraise(
                e,
                'While evaluation literal: "{}" with context: {}'.format(
                    literal,
                    ', '.join(context.keys())
                )
            )

    def _find_file(self, filename):
        from zerotk.easyfs._exceptions import FileNotFoundError

        filenames = []
        for i_include_path in self.include_paths:
            filenames.append(i_include_path + '/' + filename)

        for i_filename in filenames:
            if IsFile(i_filename):
                return i_filename

        raise FileNotFoundError(filename)