root/cly/trunk/doc/video1.py

Revision 428, 2.9 kB (checked in by athomas, 1 year ago)

cly:

  • Added a new video1.py.
  • Fixed cly.all so it works.
  • Alias can now target multiple nodes: Alias('/foo/*')
  • Fixed a couple of bugs in cly.extra, including making integrate

actually work.

  • Property svn:eol-style set to native
Line 
1 # To demonstrate how easy it is to create interactive shells with CLY, I'm
2 # going to write a simple interface to BeautifulSoup.
3
4 import sys
5 import re
6 from cly.all import *
7 from urllib2 import urlopen
8 from BeautifulSoup import BeautifulSoup
9
10 # I'll start with three basic commands:
11 #
12 #  fetch <uri>
13 #  find tag <tag>
14 #  find text <regex>
15 #
16 # And there we have it. Three commands built up in a very short amount of
17 # time. Enjoy.
18
19 # For the purposes of this demonstration we'll use a global to store the
20 # current page. You could just as easily use a class member, and all callbacks
21 # could also be methods.
22 page = None
23
24 def fetch(uri):
25     global page
26     content = urlopen(uri).read()
27     page = BeautifulSoup(content)
28     # Whoops
29
30 def find_tag(tag):
31     for t in page(tag):
32         print t
33
34 def find_text(text):
35     for t in page(text=re.compile(text)):
36         print t
37
38 # First we define the grammar. Now we'll fill it out a bit more. Each Node
39 # defines a token in the grammar.
40 #
41 # We've used a couple of new node types here. The first is a Variable, which
42 # is mapped to the arguments in the final Action callback. An Action is a
43 # terminal node in the syntax, and defines what function to call to perform
44 # the action.
45 grammar = Grammar(
46     fetch=Node('Fetch page to interrogate')(
47         # What's going on? This is due to the fact that the default pattern
48         # used to match tokens is a basic word match... To override this we
49         # can pass pattern=r'...' to the Variable constructor...
50         # We've been a little too liberal with our pattern...Fortunately there
51         # is a built in node that matches a URI: cly.types.URI
52         uri=URI('URI of page')(
53             Action('Fetch page', fetch)
54         ),
55     ),
56     # Obviously we don't want the "find" command to be used if we don't have
57     # a valid page... Fortunately, the 'valid()' method can be overridden to
58     # achieve this:
59     find=Node('Find objects in page', valid=lambda context: page)(
60         tag=Node('Find tags')(
61             tag=Variable('Tag to search for')(
62                 Action('Find tags', find_tag)
63             )
64         ),
65         text=Node('Find text')(
66             # Need to be a bit more permissive with our pattern...
67             # Displaying <text> for the user is nice, but not explicit enough
68             # about what the grammar actually expects, ie. a regex. We can
69             # override the node help to achieve this.
70             text=Variable('Text to search for', pattern=r'.+')(
71                 Action('Find text', find_text)
72             )
73         ),
74     ),
75 )
76
77 # All non-keyword arguments passed to a node "call" are treated as anonymous
78 # nodes. eg. Node('Foo')(Node('Bar'), Node('Baz'))
79
80 # Next, we interact with the user. Nice, though we want to change the
81 # application and prompt... The application is, by default, used to build
82 # a prompt, if not provided, and to store the history
83 # (~/.<application>_history).
84 quickstart(grammar, application='soupsh', prompt='> ')
Note: See TracBrowser for help on using the browser.