Changeset 551

Show
Ignore:
Timestamp:
06/10/08 21:04:24 (3 months ago)
Author:
athomas
Message:

Added Conditional node type, fixes #58.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • cly/trunk/cly/builder.py

    r550 r551  
    2222 
    2323 
    24 __all__ = ['Node', 'Alias', 'Apply', 'Action', 'Variable', 'Grammar', 
    25            'XMLGrammar', 'Help', 'LazyHelp', 'Word', 'Keyword', 'String', 
    26            'URI', 'LDAPDN', 'Integer', 'Float', 'IP', 'Hostname', 'Host', 
    27            'EMail', 'File', 'Boolean'] 
     24__all__ = [ 
     25    'Node', 'Masquerade', 'Alias', 'Conditional', 'Apply', 'Action', 
     26    'Variable', 'Grammar', 'XMLGrammar', 'Help', 'LazyHelp', 'Word', 'Keyword', 
     27    'String', 'URI', 'LDAPDN', 'Integer', 'Float', 'IP', 'Hostname', 'Host', 
     28    'EMail', 'File', 'Boolean', 
     29    ] 
    2830__docformat__ = 'restructuredtext en' 
    2931 
     
    456458 
    457459 
    458 class Alias(Node): 
     460class Masquerade(Node): 
     461    """A node that masquerades as other nodes. 
     462 
     463    Masquerade is a general-purpose tool for dynamically inserting nodes into 
     464    the grammar. Implementations should override the ``masqueraded()`` method. 
     465 
     466    Use cases: 
     467 
     468      - Conditionally present nodes. 
     469      - Dynamically generated nodes. 
     470      - Aliases for other parts of the grammar. 
     471 
     472    >>> from cly.parser import Parser 
     473    >>> class Privileged(Masquerade): 
     474    ...     authenticated = False 
     475    ...     def masqueraded(self, context): 
     476    ...         if not self.authenticated: 
     477    ...             return [] 
     478    ...         shutdown = Node(Action(self.shutdown), name='shutdown') 
     479    ...         return [shutdown] 
     480    ...     def shutdown(self): 
     481    ...         print 'shutdown()' 
     482    >>> privileged = Privileged() 
     483    >>> parser = Parser(Grammar(privileged, one=Node())) 
     484    >>> parser.execute('shutdown') 
     485    Traceback (most recent call last): 
     486    ... 
     487    InvalidToken: invalid token 'shutdown' 
     488    >>> privileged.authenticated = True 
     489    >>> parser.execute('shutdown') 
     490    shutdown() 
     491    """ 
     492 
     493    def masqueraded(self, context): 
     494        """Return a sequence of all masqueraded nodes. 
     495 
     496        :param context: Parse context. 
     497        :returns: Sequence of Nodes. 
     498        """ 
     499        raise NotImplementedError 
     500 
     501    def selected(self, context, match): 
     502        raise SystemError('Masqueraded nodes should never be selected') 
     503 
     504    def follow(self, context): 
     505        return list(self.masqueraded(context)) 
     506 
     507    def visible(self, context): 
     508        for node in self.masqueraded(context): 
     509            if node.visible(context): 
     510                return True 
     511        return False 
     512 
     513    def valid(self, context): 
     514        for node in self.masqueraded(context): 
     515            if node.valid(context): 
     516                return True 
     517        return False 
     518 
     519 
     520class Alias(Masquerade): 
    459521    """An alias for another node, or set of nodes. 
    460522 
     
    493555                      *anonymous, **kwargs) 
    494556 
    495     def valid(self, context): 
    496         for node in self.follow(context): 
    497             if node.valid(context): 
    498                 return True 
    499         return False 
    500  
    501     def visible(self, context): 
    502         for node in self.follow(context): 
    503             if node.visible(context): 
    504                 return True 
    505         return False 
    506  
    507     def selected(self, context, match): 
    508         """This node was selected by the parser.""" 
    509         raise Error('Alias nodes should never be selected') 
    510  
    511     def follow(self, context): 
     557    def masqueraded(self, context): 
    512558        """Return an iterable of all aliased nodes.""" 
    513559        root = self 
     
    533579        return '<%s:%s for %s>' % (self.__class__.__name__, self.path(), 
    534580                                   self.target) 
     581 
     582 
     583class Conditional(Masquerade): 
     584    """A set of conditional nodes. 
     585 
     586    A node that masquerades as others, based on a condition function. 
     587 
     588    :param condition: A callable with the signature ``condition(context)``. 
     589                      Returns True if masqueraded nodes are accessible. 
     590 
     591    All other arguments are passed through to the default ``Node`` constructor. 
     592 
     593    >>> from cly.parser import Parser 
     594    >>> active = False 
     595    >>> parser = Parser(Grammar(Conditional(lambda c: active, one=Node()))) 
     596    >>> parser.parse('one') 
     597    <Context command:'one' remaining:'one'> 
     598    >>> active = True 
     599    >>> parser.parse('one') 
     600    <Context command:'one' remaining:''> 
     601    """ 
     602 
     603    def __init__(self, condition, *args, **kwargs): 
     604        kwargs['condition'] = condition 
     605        super(Conditional, self).__init__(*args, **kwargs) 
     606 
     607    def masqueraded(self, context): 
     608        if not self.condition(context): 
     609            return [] 
     610        return Node.children(self, context) 
    535611 
    536612 
  • cly/trunk/.todo

    r481 r551  
    1919        Figure out why rlext.py dies when the parser is used... 
    2020    </note> 
     21    <note priority="veryhigh" time="1213113286"> 
     22        Clarify/clean-up how with_context/with_user_context/user_context is used. 
     23    </note> 
    2124</todo>