Пример #1
0
 def __init__(self, stem=None, choices=None, feedback=None, comment=None):
     super(multiplechoice, self).__init__()
     self.children.append(Join.as_element(stem or []))
     self.children.append(_choices_cls(choices or []))
     self.children.append(feedback or Join([]))
     self.children.append(comment or Join([]))
     self.id = id(self)
Пример #2
0
        def process(path):
            '''Process a TeX document file'''

            # Read and process full TeX file
            with open(path, encoding='utf8') as F:
                tex = TeX(F.read(), context=context)

            # Remove title/author/etc data
            if strip_meta:
                elements = tex.document.clear()
                preamble, _, elements = partition_type(elements, latex.maketitle)
                return Join(elements or preamble)
            else:
                return Join(tex.document.clear())
Пример #3
0
    def revalue_alttex(self, section, idx, **kwds):
        '''Picks up the correct option'''

        # Compute a predictable shuffling from the idx argument
        stripped_src = self.options.source()
        stripped_src = ''.join(stripped_src.split())
        random.seed(stripped_src + str(idx))
        options = self.options.revalue('alttex', section, idx, **kwds)
        L = options.children.clear()
        random.shuffle(L)

        # Insert elements in shufle points and return body
        body = self.body.revalue('alttex', section, idx, **kwds)
        for spoint in walk_items(body, shufflepoint):
            spoint.replace_by(L.pop())

        # Create return element
        new = Join(self.body.children.clear())
        return new if len(new) != 1 else new[0]
Пример #4
0
    def render_table(self, rows=None, cols=None, idx=None, section=None):
        '''Render choices in a table'''

        if rows is None and cols is None:
            raise ValueError('at least cols or rows must be specified')

        # Define shape for the table
        N = len(self)
        if cols is None:
            cols = math.ceil(N / rows)
        else:
            rows = math.ceil(N / cols)

        final = latex.tabular.empty(rows, cols, lines=False)  # @UndefinedVariable
        cell_choice = zip(final.iter_cells(transpose=True), self.user_choices())
        for idx, (cell, choice) in enumerate(cell_choice):
            label = Text('(%s) ' % letter(idx))
            cell.replace_by(Join([label] + choice.clear()))

        final.set_alignment('left')
        return final
Пример #5
0
    def invoke_body(cls, job, tokens, new):
        data = super(multiplechoice, cls).invoke_body(job, tokens, new)
        data = Join(data)

        # Get comments and feedback
        new.feedback = Join.as_element([ x.unlinked() for x in data if isinstance(x, feedback) ])
        new.comment = Join.as_element([ x.unlinked() for x in data if isinstance(x, comment) ])

        # Discard all data after choices
        try:
            choices_ = data.get(choices)
            [ x.unlink() for x in choices_.get_siblings_next() ]
        except ValueError:
            choices_ = choices()

        # Reorganize elements
        new.choices = choices_.unlinked()
        new.stem = Join.as_element(strip(data.clear()))
        new.id = id(new)

        return []
Пример #6
0
    def user_choices(self, idx=None, section=None):
        r'''Iterates over the user-visible data for each choice, discarding all 
        commands such as \correct, \feedback, etc'''

        for choice in self:
            try:
                choice.get(correct)
                is_correct = True
            except ValueError:
                is_correct = False

            choice = choice.copy()
            choice.remove_all(correct)
            choice.remove_all(feedback)
            choice.remove_all(comment)
            choice = Join(choice.clear())

            if is_correct:
                ifdata = choice.copy().revalue('alttex', idx, 'answers')
                ifdata = r'\textcolor{red}{\textbf{<<}~ %s ~\textbf{>>}}' % ifdata.source()
                ifdata = TeXString(ifdata)
                choice = Join([altcond(['answers'], [ifdata], [choice.copy()])])
            yield choice
Пример #7
0
    def revalue_template(self, idx, **kwds):
        for i, child in enumerate(self.children):
            new = child.revalue('template', idx, **kwds)
            if new is not child:
                self.children[i] = new

        stem, choices, feedback, comment = self.clear()
        opts = dict(self.options or {})
        final = Join()
        final.add(stem)
        final.add(TeXString('\n%\n\\par\\smallskip\n%\n'))

        # See if choices needs to be populated from vars
        if opts.get('varchoices') is not None:
            varchoices = opts['varchoices']
            varchoices = '0' if varchoices is True else varchoices
            if varchoices.isdigit():
                varchoices = 'choices' + varchoices

            # Get choices object
            choices = var.get_variable(self, varchoices)

            # Apply options in choices object
            if opts.get('shuffle'):
                del opts['shuffle']
                choices.shuffle()

            if opts.get('sort'):
                del opts['sort']
                choices.sort()

            choices = choices.texfy()

        # Shuffle choices, if required
        if opts.get('shuffle', False):
            data = choices.clear()
            seed = self.id + idx
            random.seed(seed)
            random.shuffle(data)
            choices.add(data)

        # Format choices depending on the arguments
        if opts.get('horizontal', False):
            final.add(choices.render_horizontal(idx=idx))
        elif opts.get('rows', None) is not None:
            final.add(choices.render_table(rows=int(opts['rows']), idx=idx))
        elif opts.get('cols', None) is not None:
            final.add(choices.render_table(cols=int(opts['cols']), idx=idx))
        elif opts.get('vertical', True):
            choices = final.add(choices.render_vertical(idx=idx))

        # Adds an extra spacing after choices
        final.add(TeXString('\n%\n\\endgraf\\smallskip{}\n%\n'))

        # Print feedback, comments, etc, depending on the section
        return Group('\\begingroup\n', final.clear(), '\n\\endgroup')
Пример #8
0
    def render_horizontal(self, idx=None, section=None):
        '''Render choices horizontally'''

        final = Join()
        final.add(TeXString(' \quad '))
        for idx, choice in enumerate(self.user_choices(idx=idx, section=section)):
            final.add(Text('(%s) ' % letter(idx)))
            final.add(choice.copy())
            final.add(TeXString(' \qquad '))
        final.pop()
        return final
Пример #9
0
    def invoke_body(cls, job, tokens, new):
        '''Read the list of children and find the shuffle points and its 
        possible values in the data stream'''

        options = []
        body = Join(job.read_all(tokens))

        while True:
            # we put this in a while loop in order to process only the first
            # occurrence of a string with a shuffle block opening
            # The workload is:
            #    1) find the first string matching with a '<<'
            #    2) extract the contents until a '>>' is found
            #    3) save it and the previous element into the options list
            #    4) repeat the operation with a new walk_items() search
            #    5) stop repeating when walk_items() finds no matching string
            #
            for obj in walk_items(body, str):
                # Search for the beginning of the shuffle block
                if '<<' in obj:
                    pre, _, post = obj.partition('<<')
                    obj.replace_by(pre)
                    if post:
                        pre.insert_next(post)

                    # create a shuffle point
                    spoint = shufflepoint()
                    if pre:
                        pre.insert_next(spoint)
                    else:
                        pre.replace_by(spoint)
                else:
                    continue

                # Search for the closing tag for the shuffle block
                option = []
                for obj in spoint.get_siblings_next():
                    if isinstance(obj, str) and '>>' in obj:
                        data, _, post = obj.partition('>>')
                        option.append(data)
                        obj.replace_by(post)
                        break
                    else:
                        obj.unlink()
                        option.append(obj)
                else:
                    raise RuntimeError('closing >> block not found!')

                if len(option) == 1:
                    option = option[0]
                else:
                    option = Join(option)

                options.append(option)
            # if the walk_items loop complete without finding any match for a
            # opening block, break the main while loop.
            else:
                break

        # We don't want to extend our children
        # Let us add elements to the existing options and body groups
        new.options.children.extend(options)
        new.body.children.extend(body.children.clear())

        return []
Пример #10
0
 def __init__(self, options=None, tex=None):
     super(shuffle, self).__init__()
     self.children.extend([options or Join(), tex or Join()])