| 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 | ] |
|---|
| 458 | | class Alias(Node): |
|---|
| | 460 | class 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 | |
|---|
| | 520 | class Alias(Masquerade): |
|---|
| 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): |
|---|
| | 581 | |
|---|
| | 582 | |
|---|
| | 583 | class 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) |
|---|