Beispiel #1
0
class ParserTestCase(unittest.TestCase):
    def setUp(self):
        self.parser = Parser(TurtleDrawer())
        self.source = ["p 3"]

    def test_parse_exists(self):
        """Test to confirm that the parser has a method called parse"""
        self.assertTrue("parse" in dir(Parser))

    def test_parse_executes(self):
        """Test to confirm that the parser's method parse runs without error"""
        raised = False
        # noinspection PyBroadException
        try:
            self.parser.parse(self.source)
        except Exception:
            raised = True
        self.assertFalse(raised, "Error Raised")

    def test_source_valid(self):
        """Test to confirm source stored in parser is valid"""
        self.parser.parse(self.source)
        self.assertEqual(self.parser.source, self.source)
Beispiel #2
0
 def setUp(self):
     self.parser = Parser(TurtleDrawer())
     self.source = ["p 3"]
Beispiel #3
0
 def setUp(self):
     self.source_reader = SourceReader(Parser(TurtleDrawer()))
    >>> source_reader.source = ['p 3', 'x 5', 'y 5', 'd' ,'e 5' ,'n 5' ,'w 5' ,'s 5' ,'u']
    >>> source_reader.go()
    Selected pen 3.0
    Gone to X=5.0
    Gone to Y=5.0
    Pen down
    drawing line of length 5.0 at 0 degrees
    drawing line of length 5.0 at 90 degrees
    drawing line of length 5.0 at 180 degrees
    drawing line of length 5.0 at 270 degrees
    Pen lifted

    End doctest
    """
    def __init__(self, parser):
        super().__init__(parser)
        self.script_extension = '.tigr'

    def go(self):
        self.parser.parse(self.source)


if __name__ == '__main__':
    import doctest
    from TIGrExParser import Parser
    from TIGrExTurtleDrawer import TurtleDrawer

    source_reader = SourceReader(Parser(TurtleDrawer()))
    doctest.testmod(verbose=3)
Beispiel #5
0
class TIGrEx(cmd.Cmd):
    """Main application controller for TIGrEx


    Begin doctest - Written with Jonathan Holdaway and Sean Ryan 24/08/2019

    >>> app.do_drawer('turtle')
    Now using Turtle Drawer
    >>> app.do_pen(2)
    Selected pen 2
    >>> app.do_x(5)
    Gone to X=5
    >>> app.do_y(5)
    Gone to Y=5
    >>> app.do_down()
    Pen down
    >>> app.do_east(50)
    drawing line of length 50 at 0 degrees
    >>> app.do_north(50)
    drawing line of length 50 at 90 degrees
    >>> app.do_west(50)
    drawing line of length 50 at 180 degrees
    >>> app.do_south(50)
    drawing line of length 50 at 270 degrees
    >>> app.do_up()
    Pen lifted

    Test script running
    >>> app.do_clear()
    Cleared drawing
    >>> app.do_run('script')
    Running script: script.tigr
    Selected pen 2.0
    Gone to X=5.0
    Gone to Y=15.0
    Pen down
    drawing line of length 2.0 at 180 degrees
    drawing line of length 1.0 at 90 degrees
    drawing line of length 2.0 at 0 degrees
    drawing line of length 12.7 at 270 degrees
    Pen lifted

    End doctest
    """
    intro = 'Welcome to Extended Tiny Interpreted Graphics.\n' \
            'Use "drawer" command to choose graphics library.\n' \
            'Enter ? for help.'
    prompt = 'TIGrEx >: '

    def __init__(self):
        super().__init__()
        self.drawer = None
        self.parser = None
        self.source_reader = None

    def setup(self, drawer):
        # Generic setup for classes
        self.drawer = drawer
        self.parser = Parser(self.drawer)
        self.source_reader = SourceReader(self.parser)

    def do_drawer(self, arg):
        """Select graphics library to draw with.
Available drawers:
text, turtle
-----"""
        if self.drawer:
            self.drawer.shutdown()
        if arg.lower() == 'text':
            self.setup(TextDrawer())
        elif arg.lower() == 'turtle':
            self.setup(TurtleDrawer())
        else:
            print('Please select a valid drawer.')

    def do_clear(self, arg=None):
        del arg
        try:
            self.parser.draw_clear()
        except AttributeError as exception:
            if self.drawer is None:
                # If no drawer is set then don't allow a command to run
                print(
                    'Please select a drawer before trying to run drawer commands.'
                )
            else:
                print(exception)

    def do_up(self, arg=None):
        """Stop drawing.
-----"""
        del arg
        try:
            self.parser.draw_pen_up()
        except AttributeError as exception:
            # If no drawer is set then don't allow a command to run
            if self.drawer is None:
                print(
                    'Please select a drawer before trying to run drawer commands.'
                )
            else:
                print(exception)

    def do_down(self, arg=None):
        """Start drawing.
-----"""
        del arg
        try:
            self.parser.draw_pen_down()
        except AttributeError as exception:
            # If no drawer is set then don't allow a command to run
            if self.drawer is None:
                print(
                    'Please select a drawer before trying to run drawer commands.'
                )
            else:
                print(exception)

    def do_north(self, arg):
        """Draw north by a specified amount.
-----"""
        try:
            self.parser.data = int(arg)
            self.parser.command = 'north'
            self.parser.draw_line_data(self.parser.data)
        except ValueError:
            print('This command only takes numbers')
        except AttributeError as exception:
            # If no drawer is set then don't allow a command to run
            if self.drawer is None:
                print(
                    'Please select a drawer before trying to run drawer commands.'
                )
            else:
                print(exception)

    def do_south(self, arg):
        """Draw south by a specified amount.
-----"""
        try:
            self.parser.data = int(arg)
            self.parser.command = 'south'
            self.parser.draw_line_data(self.parser.data)
        except AttributeError as exception:
            # If no drawer is set then don't allow a command to run
            if self.drawer is None:
                print(
                    'Please select a drawer before trying to run drawer commands.'
                )
            else:
                print(exception)

    def do_east(self, arg):
        """Draw east by a specified amount.
-----"""
        try:
            self.parser.data = int(arg)
            self.parser.command = 'east'
            self.parser.draw_line_data(self.parser.data)
        except ValueError:
            print('This command only takes numbers')
        except AttributeError as exception:
            # If no drawer is set then don't allow a command to run
            if self.drawer is None:
                print(
                    'Please select a drawer before trying to run drawer commands.'
                )
            else:
                print(exception)

    def do_west(self, arg):
        """Draw west by a specified amount.
-----"""
        try:
            self.parser.data = int(arg)
            self.parser.command = 'west'
            self.parser.draw_line_data(self.parser.data)
        except ValueError:
            print('This command only takes numbers')
        except AttributeError as exception:
            # If no drawer is set then don't allow a command to run
            if self.drawer is None:
                print(
                    'Please select a drawer before trying to run drawer commands.'
                )
            else:
                print(exception)

    def do_x(self, arg):
        """Set X position of the pen.
-----"""
        try:
            self.parser.data = int(arg)
            self.parser.draw_goto_x(self.parser.data)
        except ValueError:
            print('This command only takes numbers')
        except AttributeError as exception:
            # If no drawer is set then don't allow a command to run
            if self.drawer is None:
                print(
                    'Please select a drawer before trying to run drawer commands.'
                )
            else:
                print(exception)

    def do_y(self, arg):
        """Set Y position of the pen.
-----"""
        try:
            self.parser.data = int(arg)
            self.parser.draw_goto_y(self.parser.data)
        except ValueError:
            print('This command only takes numbers')
        except AttributeError as exception:
            # If no drawer is set then don't allow a command to run
            if self.drawer is None:
                print(
                    'Please select a drawer before trying to run drawer commands.'
                )
            else:
                print(exception)

    def do_pen(self, arg):
        """Select preset pen.

Preset pens:
1 - colour black, size 10
2 - colour red, size 10
3 - colour blue, size 10
-----"""
        try:
            self.parser.data = int(arg)
            self.parser.draw_select_pen(self.parser.data)
        except ValueError:
            print('This command only takes numbers')
        except AttributeError as exception:
            # If no drawer is set then don't allow a command to run
            if self.drawer is None:
                print(
                    'Please select a drawer before trying to run drawer commands.'
                )
            else:
                print(exception)

    def do_run(self, arg):
        """Load a script and run it.
-----"""
        try:
            # Search for file without extension, if the file isn't found try with extension
            # Using multi-line and case insensitive for regex search
            if re.search(
                    r'^.*\.(' + self.source_reader.script_extension + r')$',
                    arg, re.M | re.I):
                file = arg
            else:
                file = arg + self.source_reader.script_extension
            print('Running script:', file)
            self.source_reader.source = [
                line.rstrip('\n') for line in open(file)
            ]
        except FileNotFoundError:
            # If file is found in search without the script extension alert that TIGr only reads .tigr scripts
            if not re.search(
                    r'^.*\.(' + self.source_reader.script_extension + r')$',
                    arg, re.M | re.I):
                print('Script not found. Enter a valid file name.')
            else:
                print(
                    f'Script not found. TIGrEx only reads {self.source_reader.script_extension} files as scripts.'
                )
        except AttributeError as exception:
            # If no drawer is set then don't allow a script to run
            if self.drawer is None:
                print('Please select a drawer before trying to run scripts.')
            else:
                print(exception)
        else:
            # Start parsing the script
            self.source_reader.file_name = arg
            self.source_reader.go()

    @staticmethod
    def do_quit(arg):
        """Closes the program.
-----"""
        del arg
        exit()

    @staticmethod
    def do_exit(arg):
        """Closes the program.
-----"""
        del arg
        exit()

    @staticmethod
    def parse(arg):
        # Convert arg to a tuple
        return tuple(map(int, arg.split()))
Beispiel #6
0
 def setup(self, drawer):
     # Generic setup for classes
     self.drawer = drawer
     self.parser = Parser(self.drawer)
     self.source_reader = SourceReader(self.parser)
Beispiel #7
0
class TIGrEx(cmd.Cmd):
    """Main application controller for TIGrEx


    Begin doctest - Written with Jonathan Holdaway and Sean Ryan 24/08/2019

    >>> app.do_drawer('turtle')
    Now using Turtle Drawer
    >>> app.do_pen(2)
    Selected pen 2.0
    >>> app.do_x(5)
    Gone to X=5.0
    >>> app.do_y(5)
    Gone to Y=5.0
    >>> app.do_down()
    Pen down
    >>> app.do_east(50)
    drawing line of length 50.0 at 0 degrees
    >>> app.do_north(50)
    drawing line of length 50.0 at 90 degrees
    >>> app.do_west(50)
    drawing line of length 50.0 at 180 degrees
    >>> app.do_south(50)
    drawing line of length 50.0 at 270 degrees
    >>> app.do_up()
    Pen lifted

    Test script running
    >>> app.do_clear()
    Cleared drawing
    >>> app.do_run('script')
    Running script: script.tigr
    Selected pen 2.0
    Gone to X=5.0
    Gone to Y=15.0
    Pen down
    drawing line of length 2.0 at 180 degrees
    drawing line of length 1.0 at 90 degrees
    drawing line of length 2.0 at 0 degrees
    drawing line of length 12.7 at 270 degrees
    Pen lifted

    End doctest
    # """
    def __init__(self):
        super().__init__()
        self.drawer = None
        self.parser = None
        self.source_reader = None
        self.intro = 'Welcome to Extended Tiny Interpreted Graphics.\n' \
                     'Use "drawer" command to choose graphics library.\n' \
                     'Enter ? for help.'
        self.prompt = 'TIGrEx >: '
        self.script_extension = '.tigr'

    def setup(self, drawer):
        # Generic setup for classes
        self.drawer = drawer
        self.parser = Parser(self.drawer)

    def do_drawer(self, arg):
        """Select graphics library to draw with.
Available drawers:
text, turtle
-----"""
        if self.drawer:
            self.drawer.shutdown()
            self.drawer = None
        if arg.lower() == 'text':
            self.setup(TextDrawer())
        elif arg.lower() == 'turtle':
            self.setup(TurtleDrawer())
        else:
            print('Please select a valid drawer.')

    # changed all the do_ methods path to call parser.parse
    def do_clear(self, arg=None):
        del arg
        self.parser.parse({'clear'})

    def do_up(self, arg=None):
        """Stop drawing.
-----"""
        del arg
        self.parser.parse({'up'})

    def do_down(self, arg=None):
        """Start drawing.
-----"""
        del arg
        self.parser.parse({'down'})

    def do_north(self, arg):
        """Draw north by a specified amount.
-----"""
        self.parser.parse({'north ' + str(arg)})

    def do_south(self, arg):
        """Draw south by a specified amount.
-----"""
        self.parser.parse({'south ' + str(arg)})

    def do_east(self, arg):
        """Draw east by a specified amount.
-----"""
        self.parser.parse({'east ' + str(arg)})

    def do_west(self, arg):
        """Draw west by a specified amount.
-----"""
        self.parser.parse({'west ' + str(arg)})

    def do_x(self, arg):
        """Set X position of the pen.
-----"""
        self.parser.parse({'x ' + str(arg)})

    def do_y(self, arg):
        """Set Y position of the pen.
-----"""
        self.parser.parse({'y ' + str(arg)})

    def do_pen(self, arg):
        """Select preset pen.
Preset pens:
1 - colour black, size 10
2 - colour red, size 10
3 - colour blue, size 10
-----"""
        self.parser.parse({'pen ' + str(arg)})

    def do_run(self, arg):
        """Load a script and run it.
-----"""
        # Search for file without extension, if the file isn't found try with extension
        # Using multi-line and case insensitive for regex search
        # modified by Jerry Wang, this regx can not match a file name end with .tigr
        extension_check = re.search(r'^.*(' + self.script_extension + r')$',
                                    arg, re.M | re.I)
        if extension_check:
            file = arg
        else:
            file = arg + self.script_extension
        print('Running script:', file)
        try:
            raw_source = [line.rstrip('\n') for line in open(file)]
        except FileNotFoundError:
            # If file is found in search without the script extension alert that TIGr only reads .tigr scripts
            if not extension_check:
                print('Script not found. Enter a valid file name.')
            else:
                print(
                    f'Script not found.TIGrEx only reads {self.script_extension} files as scripts.'
                )
        else:
            # Start parsing the script
            self.parser.parse(raw_source)

    # extract error check into two new methods  ---- Duplicated Code
    """I realized that the way I refactored code caused another duplication bad smell
    So I put Drawer check in precmd and all data check in parser.parse where it meant to be
    """

    def precmd(self, line):
        if line is not None and line.split(' ')[0].lower() not in ('drawer',
                                                                   '?', 'exit',
                                                                   'quit'):
            if self.drawer is None:
                print(
                    'Please select a drawer before trying to run drawer commands'
                )
                return ''
            else:
                return line
        else:
            return line

    @staticmethod
    def do_quit(arg):
        """Closes the program.
-----"""
        del arg
        exit()

    @staticmethod
    def do_exit(arg):
        """Closes the program.
-----"""
        del arg
        exit()

    # It runs previous command when get '' from precmd method as return.
    # Override emptyline method to make sure it runs nothing
    def emptyline(self):
        pass
Beispiel #8
0
 def setup(self, drawer):
     # Generic setup for classes
     self.drawer = drawer
     self.parser = Parser(self.drawer)