Sophie

Sophie

distrib > Fedora > 13 > i386 > media > os > by-pkgid > 19c0846d50c5b0d671ee1dea8e95ddee > files > 43

python-cly-0.9-2.fc12.i686.rpm

# To demonstrate how easy it is to create interactive shells with CLY, I'm
# going to write a simple interface to BeautifulSoup.

import sys
import re
from cly.all import *
from urllib2 import urlopen
from BeautifulSoup import BeautifulSoup

# I'll start with three basic commands:
#
#  fetch <uri>
#  find tag <tag>
#  find text <regex>
#
# And there we have it. Three commands built up in a very short amount of
# time. Enjoy.

# For the purposes of this demonstration we'll use a global to store the
# current page. You could just as easily use a class member, and all callbacks
# could also be methods.
page = None

def fetch(uri):
    global page
    content = urlopen(uri).read()
    page = BeautifulSoup(content)
    # Whoops

def find_tag(tag):
    for t in page(tag):
        print t

def find_text(text):
    for t in page(text=re.compile(text)):
        print t

# First we define the grammar. Now we'll fill it out a bit more. Each Node
# defines a token in the grammar. 
#
# We've used a couple of new node types here. The first is a Variable, which
# is mapped to the arguments in the final Action callback. An Action is a
# terminal node in the syntax, and defines what function to call to perform
# the action.
grammar = Grammar(
    fetch=Node('Fetch page to interrogate')(
        # What's going on? This is due to the fact that the default pattern
        # used to match tokens is a basic word match... To override this we
        # can pass pattern=r'...' to the Variable constructor...
        # We've been a little too liberal with our pattern...Fortunately there
        # is a built in node that matches a URI: cly.types.URI
        uri=URI('URI of page')(
            Action('Fetch page', fetch)
        ),
    ),
    # Obviously we don't want the "find" command to be used if we don't have
    # a valid page... Fortunately, the 'valid()' method can be overridden to
    # achieve this:
    find=Node('Find objects in page', valid=lambda context: page)(
        tag=Node('Find tags')(
            tag=Variable('Tag to search for')(
                Action('Find tags', find_tag)
            )
        ),
        text=Node('Find text')(
            # Need to be a bit more permissive with our pattern...
            # Displaying <text> for the user is nice, but not explicit enough
            # about what the grammar actually expects, ie. a regex. We can
            # override the node help to achieve this.
            text=Variable('Text to search for', pattern=r'.+')(
                Action('Find text', find_text)
            )
        ),
    ),
)

# All non-keyword arguments passed to a node "call" are treated as anonymous
# nodes. eg. Node('Foo')(Node('Bar'), Node('Baz'))

# Next, we interact with the user. Nice, though we want to change the
# application and prompt... The application is, by default, used to build
# a prompt, if not provided, and to store the history
# (~/.<application>_history).
quickstart(grammar, application='soupsh', prompt='> ')