Example #1
0
    def evaluate(self):
        # Check for the first PREXEL marker
        self.start_marker()

        # Process the first class name
        first_class_diagram = ClassDiagramPart()
        first_class_diagram.name = self.class_name()

        # Optionally check for FIELD and METHOD tokens
        self.class_body(first_class_diagram)

        # Optional - Check for inheritance
        if self.inheritance():
            self.diagram.parent = first_class_diagram
        else:
            self.diagram.main = first_class_diagram

        # Optional - Check for aggregation but don't
        # consider the fields and methods following the aggregation
        # token as part of the aggregated class.In this position
        # they belong to the main class
        self.aggregation(include_following_tokens=False)

        # Process fields and methods for main class
        self.class_body(self.diagram.main)

        # Optional - Check for aggregation
        self.aggregation()

        return self.diagram
Example #2
0
    def aggregation(self, include_following_tokens=True):
        """
        Process any aggregated classes. The class process both the AGGREGATION token and
        a CLASS_NAME token for the aggregated class.
        """
        if self.current_token and self.current_token.type is Token.AGGREGATION:
            # Cache the current token
            token = self.current_token

            # Process AGGREGATION Token
            self.process_token(Token.AGGREGATION)

            # Confirm that a CLASS_NAME token follows the AGGREGATION TOKEN
            if not self.next_token_is_class_token():
                self.error("There is no class name following the aggregation.")

            # Process aggregated ClassDiagramPart. Optionally include class body
            aggregated = ClassDiagramPart()
            aggregated.name = self.class_name()

            if include_following_tokens:
                self.class_body(aggregated)

            self.diagram.aggregated = aggregated

            # Process AggregationDiagramPart
            aggregation = AggregationDiagramPart()

            # Create a list for the fields on the main ClassDiagramPart object
            if not self.diagram.main.fields:
                self.diagram.main.fields = []

            # Check that the AGGREGATION token has a name, if not
            # default to the aggregated class's name
            name = token.value["name"]
            if name:
                self.diagram.main.fields.append(name)
                aggregation.name = name
            else:
                # Generate an aggregation name from the aggregated class
                generated_name = aggregated.name.lower()
                self.diagram.main.fields.append(generated_name)
                aggregation.name = generated_name

            # Add multiplicity values
            aggregation.left_multiplicity = token.value["left_multi"]
            aggregation.right_multiplicity = token.value["right_multi"]

            # Save aggregation value to Diagram object
            self.diagram.aggregation = aggregation
Example #3
0
    def test_class_body(self):
        """
        Test the class_body() method, which processes FIELD and METHOD tokens
        """
        text = "|Airplane size color take_off()"
        lexer = Lexer(text)

        interpreter = Interpreter(lexer)
        interpreter.start_marker()

        class_diagram = ClassDiagramPart()
        class_diagram.name = interpreter.class_name()
        interpreter.class_body(class_diagram)

        self.assertEqual(class_diagram.fields, ["size", "color"])
        self.assertEqual(class_diagram.methods, ["take_off()"])
Example #4
0
    def test_aggregation_with_missing_aggregation_name(self):
        """
        Test the aggregation() method,
        """
        text = "|Kitchen <>---> Cupboard"
        lexer = Lexer(text)

        interpreter = Interpreter(lexer)
        diagram = interpreter.diagram
        class_diagram_part = ClassDiagramPart()

        interpreter.start_marker()
        class_diagram_part.name = interpreter.class_name()
        diagram.main = class_diagram_part
        interpreter.aggregation()

        self.assertEqual(diagram.aggregation.name, "cupboard")
        self.assertEqual(diagram.main.fields, ["cupboard"])
        self.assertEqual(diagram.aggregated.name, "Cupboard")
Example #5
0
    def test_inheritance_with_error(self):
        """
        Test the inheritance() method, with an improper syntax
        """
        text = "|Kitchen >>"
        lexer = Lexer(text)

        interpreter = Interpreter(lexer)
        class_diagram_part = ClassDiagramPart()

        interpreter.start_marker()
        class_diagram_part.name = interpreter.class_name()

        # Should raise a InterpreterException
        with self.assertRaises(InterpreterException) as context:
            interpreter.inheritance()

        self.assertEqual(context.exception.args[0],
                         "Missing child class after \">>\"")
Example #6
0
    def test_inheritance(self):
        """
        Test the inheritance() method, which processes an inheritance relationship
        """
        text = "|Room height width >> Kitchen"
        lexer = Lexer(text)

        interpreter = Interpreter(lexer)
        diagram = interpreter.diagram
        class_diagram_part = ClassDiagramPart()

        interpreter.start_marker()
        class_diagram_part.name = interpreter.class_name()
        interpreter.class_body(class_diagram_part)

        if interpreter.inheritance():
            diagram.parent = class_diagram_part
        else:
            diagram.main = class_diagram_part

        self.assertEqual(diagram.parent.name, "Room")
        self.assertEqual(diagram.parent.fields, ["height", "width"])
        self.assertEqual(diagram.main.name, "Kitchen")
Example #7
0
    def inheritance(self):
        """
        Process an INHERITANCE TOKEN. Sets the parent and inheritance fields
        on the Diagram object.

         ___________               ________________ 
        |  Diagram  |<>-parent--->|ClassDiagramPart|
        |-----------|             |________________|
        |inheritance|                               
        |parent     |                               
        |___________|                               

        """
        has_inheritance = False

        if self.current_token and self.current_token.type is Token.INHERITANCE:
            inheritance = InheritanceDiagramPart()

            # Process token
            self.process_token(Token.INHERITANCE)

            # Check CLASS_NAME token follows the INHERITANCE token
            if self.next_token_is_class_token():
                child = ClassDiagramPart()

                # Determine child class name
                child.name = self.class_name()

                # Append inheritance diagram and then parent class diagram
                self.diagram.inheritance = inheritance
                self.diagram.main = child
                has_inheritance = True
            else:
                self.error("Missing child class after \">>\"")

        return has_inheritance
Example #8
0
    def test_aggregation_multi_line(self):
        """
        Test the aggregation() method using multi-line syntax
        """
        text = """
|Kitchen <>-cupboard--> Cupboard
|size
|color"""
        lexer = Lexer(text)

        interpreter = Interpreter(lexer)
        diagram = interpreter.diagram

        class_diagram_part = ClassDiagramPart()

        interpreter.start_marker()
        class_diagram_part.name = interpreter.class_name()
        diagram.main = class_diagram_part
        interpreter.aggregation(include_following_tokens=False)
        interpreter.class_body(diagram.main)

        self.assertEqual(diagram.aggregation.name, "cupboard")
        self.assertEqual(diagram.main.fields, ["cupboard", "size", "color"])
        self.assertEqual(diagram.aggregated.name, "Cupboard")