Christian Wyglendowski avatar Christian Wyglendowski committed 5c01388

* Added not_, is_ hasClass and eq traversal methods (though not all are directly related to traversal imo).
* Expanded the filter method to take a callable as in jQuery.
* Added a section on traversal to the README.txt doctests.
* Moved the traversal tests into their own class in test.py.

Comments (0)

Files changed (3)

pyquery/README.txt

     >>> p.attr.style
     'font-size: 17px'
 
+Traversing
+----------
+
+Some jQuery traversal methods are supported.  For instance, you can filter the selection list
+using a string selector::
+
+    >>> d('p').filter('.hello')
+    [<p#hello.hello>]
+
+Filtering can also be done using a function::
+
+    >>> d('p').filter(lambda i: i == 1)
+    [<p#test>]
+
+Filtering functions can refer to the current element as 'this', like in jQuery::
+
+    >>> d('p').filter(lambda i: PyQuery(this).text() == 'you know Python rocks')
+    [<p#hello.hello>]
+
+The opposite of filter is not_ - it returns the items that don't match the selector::
+
+    >>> d('p').not_('.hello')
+    [<p#test>]
+
+It is possible to select a single element with eq::
+
+    >>> d('p').eq(0)
+    [<p#hello.hello>]
+
+The is_ method lets you query if any current elements match the selector::
+
+    >>> d('p').eq(0).is_('.hello')
+    True
+    >>> d('p').eq(1).is_('.hello')
+    False
+
+hasClass allows for checking for the presence of a class by name::
+
+    >>> d('p').eq(0).hasClass('hello')
+    True
+    >>> d('p').eq(1).hasClass('hello')
+    False
+
+You can find nested elements::
+
+    >>> d('p').find('a')
+    [<a>, <a>]
+    >>> d('p').eq(1).find('a')
+    [<a>]
+
+Breaking out of a level of traversal is also supported using end::
+
+    >>> d('p').find('a').end()
+    [<p#hello.hello>, <p#test>]
+    >>> d('p').eq(0).end()
+    [<p#hello.hello>, <p#test>]
+    >>> d('p').filter(lambda i: i == 1).end()
+    [<p#hello.hello>, <p#test>]
+
 Manipulating
 ------------
 

pyquery/pyquery.py

     ##############
 
     def filter(self, selector):
-        """Filter elements in self using selector."""
-        return self.__class__(selector, self, **dict(parent=self))
+        """Filter elements in self using selector (string or function)."""
+        if not callable(selector):
+            return self.__class__(selector, self, **dict(parent=self))
+        else:
+            elements = []
+            try:
+                for i, this in enumerate(self):
+                    selector.func_globals['this'] = this
+                    if selector(i):
+                        elements.append(this)
+            finally:
+                del selector.func_globals['this']
+            return self.__class__(elements, **dict(parent=self))
+
+    def not_(self, selector):
+        """Return elements that don't match the given selector."""
+        exclude = set(self.__class__(selector, self))
+        return self.__class__([e for e in self if e not in exclude], **dict(parent=self))
+
+    def is_(self, selector):
+        """Returns True if selector matches at least one current element, else False."""
+        return bool(self.__class__(selector, self))
+
+    def hasClass(self, name):
+        return self.is_('.%s' % name)
 
     def find(self, selector):
         """Find elements using selector traversing down from self."""
             elements.extend(r)
         return self.__class__(elements, **dict(parent=self))
 
+    def eq(self, index):
+        """Return PyQuery of only the element with the provided index."""
+        return self.__class__([self[index]], **dict(parent=self))
+
     def each(self, func):
         """apply func on each nodes
         """
            </html>
            """
 
-    html3 = """
-           <html>
-            <body>
-              <div id="node1"><span>node1</span></div>
-              <div id="node2"><span>node2</span><span> booyah</span></div>
-            </body>
-           </html>
-           """
-
     def test_selector_from_doc(self):
         doc = etree.fromstring(self.html)
         assert len(self.klass(doc)) == 1
         assert isinstance(n, self.klass)
         assert n._parent is e
 
+class TestTraversal(unittest.TestCase):
+    klass = pq
+    html = """
+           <html>
+            <body>
+              <div id="node1"><span>node1</span></div>
+              <div id="node2" class="node3"><span>node2</span><span> booyah</span></div>
+            </body>
+           </html>
+           """
+
     def test_filter(self):
         assert len(self.klass('div', self.html).filter('.node3')) == 1
         assert len(self.klass('div', self.html).filter('#node2')) == 1
+        assert len(self.klass('div', self.html).filter(lambda i: i == 0)) == 1
+
+    def test_not(self):
+        assert len(self.klass('div', self.html).not_('.node3')) == 1
+
+    def test_is(self):
+        assert self.klass('div', self.html).is_('.node3')
+        assert not self.klass('div', self.html).is_('.foobazbar')
 
     def test_find(self):
-        assert len(self.klass('#node1', self.html3).find('span')) == 1
-        assert len(self.klass('#node2', self.html3).find('span')) == 2
-        assert len(self.klass('div', self.html3).find('span')) == 3
+        assert len(self.klass('#node1', self.html).find('span')) == 1
+        assert len(self.klass('#node2', self.html).find('span')) == 2
+        assert len(self.klass('div', self.html).find('span')) == 3
 
     def test_end(self):
-        assert len(self.klass('div', self.html3).find('span').end()) == 2
-        assert len(self.klass('#node2', self.html3).find('span').end()) == 1
+        assert len(self.klass('div', self.html).find('span').end()) == 2
+        assert len(self.klass('#node2', self.html).find('span').end()) == 1
 
 def application(environ, start_response):
     req = Request(environ)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.