Skip to content

Instantly share code, notes, and snippets.

@ffunenga
Last active December 19, 2015 12:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ffunenga/5955574 to your computer and use it in GitHub Desktop.
Save ffunenga/5955574 to your computer and use it in GitHub Desktop.
Identification of implicit element as a search problem
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# author: Filipe Funenga
# date: 8 Jul 2013
# Basic Elements in a CLI specification. Just skip ahead.
class Leaf:
def __init__(self, name, value):
self.name = name
self.value = value
def __repr__(self):
return '%s("%s", %s)' % (
self.__class__.__name__, self.name, self.value)
class Command(Leaf):
def __repr__(self):
return self.name
class Argument(Leaf):
def __repr__(self):
return self.name
class Option(Leaf):
def __repr__(self):
return self.name
class Branch:
def __init__(self, children):
self.children = children
def __repr__(self):
return '%s(%s)' % (self.__class__.__name__, str(self.children))
class Required(Branch):
def __repr__(self):
return '(%s)' % ' '.join([str(c) for c in self.children])
class Optional(Branch):
def __repr__(self):
return '[%s]' % ' '.join([str(c) for c in self.children])
class Either(Branch):
def __repr__(self):
return ' | '.join([str(c) for c in self.children])
class OneOrMore(Branch):
def __repr__(self):
return ' '.join([str(c) for c in self.children]) + '...'
# Search Tree Node
class Node:
def __init__(self, pattern):
assert isinstance(pattern, Required)
self.key = ''.join([('w' if isinstance(elem, Command) or
isinstance(elem, Argument) else
'o' if isinstance(elem, Option) else '')
for elem in pattern.children])
self.pattern = pattern
self.children = self.__get_children()
def __get_children(self):
for child in self.pattern.children:
if isinstance(child, Branch):
children = []
if isinstance(child, Required):
__temp = [([c] if c is not child else child.children)
for c in self.pattern.children]
children.append(Required([i for l in __temp for i in l]))
elif isinstance(child, Optional):
children.append(Required([c for c in self.pattern.children
if c is not child]))
__temp = [([c] if c is not child else child.children)
for c in self.pattern.children]
children.append(Required([i for l in __temp for i in l]))
elif isinstance(child, Either):
for elem in child.children:
__temp = [([c] if c is not elem else elem.children)
for c in self.pattern.children]
children.append(Required([i for l in __temp for i in l]))
elif isinstance(child, OneOrMore):
print child
return children
return []
def __repr__(self):
return str(self.pattern)
# Main function
def main():
# Define the CLI pattern here. This structure is usually retrieved from the
# CLI specification (known as docopt string). Some examples are provided
# bellow.
def pattern1(): # Usage: ./prog [<file>] update
argv1 = Optional([Argument('<file>', None)])
argv2 = Command('update', None)
return Required([argv1, argv2])
def pattern2(): # Usage: ./prog [<file> [<template>]] update
argv1 = Optional([Argument('<file>', None),
Optional([Argument('<template>', None)])])
argv2 = Command('update', None)
return Required([argv1, argv2])
def pattern3(): # Usage: ./prog [<file>] update [<template>]
argv1 = Optional([Argument('<file>', None)])
argv2 = Command('update', None)
argv3 = Optional([Argument('<template>', None)])
return Required([argv1, argv2, argv3])
argv = pattern1() # change this function to try other patterns
print 'argv:', argv
# Search pattern tree (either using DFS or BFS) and collects leaf nodes.
# These new leaf nodes need to checked if they are ambiguous: if the
# pattern of skipped options (i.e. only commands and arguments) is not
# unique, then the CLI pattern is ambiguous.
print '---', 'tree search:', 'DFS'
search = {'DFS': -1, 'BFS': 0}['DFS']
idx = 0
leafs = {}
queue = [argv]
while queue:
node = queue.pop(search)
print 'idx: %d,' % idx, 'node:', node
idx += 1
node = Node(node)
if len(node.children):
queue.extend(node.children)
else:
if not leafs.has_key(node.key):
leafs[node.key] = node.pattern
else:
exit('Ambiguous pattern in "%s" vs "%s"' % (
str(leafs[node.key]), str(node.pattern)))
# Use collected leafs to make something. In this case, it just prints out
# the pattern.
print '---'
print 'leafs:'
for k,v in leafs.iteritems():
print ' ', k, v
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment