<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -4,6 +4,7 @@
 
   * Added mailing list and ticket tracking information to the README.txt
   * Sets ENV['PATH'] on windows if it doesn't exist
+  * Caching results of NodeSet#[] on Document
 
 === 1.0.4
 </diff>
      <filename>History.txt</filename>
    </modified>
    <modified>
      <diff>@@ -52,7 +52,22 @@ static VALUE index_at(VALUE self, VALUE number)
   if(i &lt; 0)
     i = i + node_set-&gt;nodeNr;
 
-  return Nokogiri_wrap_xml_node(node_set-&gt;nodeTab[i]);
+  VALUE document = rb_funcall(self, rb_intern(&quot;document&quot;), 0);
+  if(Qnil == document)
+    rb_raise(rb_eRuntimeError, &quot;You forgot to set a document.&quot;);
+
+  VALUE index = INT2NUM((int)node_set-&gt;nodeTab[i]);
+
+  VALUE node_cache = rb_funcall(document, rb_intern(&quot;node_cache&quot;), 0);
+
+  VALUE node = rb_hash_aref(node_cache, index);
+
+  if(Qnil == node) {
+    node = Nokogiri_wrap_xml_node(node_set-&gt;nodeTab[i]);
+    rb_hash_aset(node_cache, index, node);
+  }
+
+  return node;
 }
 
 static void deallocate(xmlNodeSetPtr node_set)
@@ -101,7 +116,7 @@ static VALUE allocate(VALUE klass)
 
 VALUE Nokogiri_wrap_xml_node_set(xmlNodeSetPtr node_set)
 {
-    return Data_Wrap_Struct(cNokogiriXmlNodeSet, 0, deallocate, node_set);
+  return Data_Wrap_Struct(cNokogiriXmlNodeSet, 0, deallocate, node_set);
 }
 
 VALUE cNokogiriXmlNodeSet ;</diff>
      <filename>ext/nokogiri/xml_node_set.c</filename>
    </modified>
    <modified>
      <diff>@@ -23,10 +23,17 @@ static VALUE node_set(VALUE self)
   xmlXPathObjectPtr xpath;
   Data_Get_Struct(self, xmlXPathObject, xpath);
 
+  VALUE node_set = Qnil;
+
   if (xpath-&gt;nodesetval)
-    return Nokogiri_wrap_xml_node_set(xpath-&gt;nodesetval);
+    node_set = Nokogiri_wrap_xml_node_set(xpath-&gt;nodesetval);
+
+  if(Qnil == node_set)
+    node_set = Nokogiri_wrap_xml_node_set(xmlXPathNodeSetCreate(NULL));
+
+  rb_funcall(node_set, rb_intern(&quot;document=&quot;), 1, rb_iv_get(self, &quot;@document&quot;));
 
-  return Nokogiri_wrap_xml_node_set(xmlXPathNodeSetCreate(NULL));
+  return node_set;
 }
 
 VALUE cNokogiriXmlXpath;</diff>
      <filename>ext/nokogiri/xml_xpath.c</filename>
    </modified>
    <modified>
      <diff>@@ -41,7 +41,19 @@ static VALUE evaluate(VALUE self, VALUE search_path)
   if(xpath == NULL) {
     rb_raise(rb_eRuntimeError, &quot;Couldn't evaluate expression '%s'&quot;, query);
   }
-  return Nokogiri_wrap_xml_xpath(xpath);
+
+  VALUE xpath_object = Nokogiri_wrap_xml_xpath(xpath);
+
+  assert(ctx-&gt;node);
+  assert(ctx-&gt;node-&gt;doc);
+  assert(ctx-&gt;node-&gt;doc-&gt;_private);
+
+  rb_funcall( xpath_object,
+              rb_intern(&quot;document=&quot;),
+              1,
+              (VALUE)ctx-&gt;node-&gt;doc-&gt;_private
+            );
+  return xpath_object;
 }
 
 /*</diff>
      <filename>ext/nokogiri/xml_xpath_context.c</filename>
    </modified>
    <modified>
      <diff>@@ -17,8 +17,9 @@ module Nokogiri
       end
 
       def make string
-        ns = XML::NodeSet.new
-        ns &lt;&lt; XML::Text.new(string, XML::Document.new)
+        doc = XML::Document.new
+        ns = XML::NodeSet.new(doc)
+        ns &lt;&lt; XML::Text.new(string, doc)
         ns
       end
 </diff>
      <filename>lib/nokogiri/hpricot.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,3 +1,3 @@
 module Nokogiri
-  VERSION = '1.0.4'
+  VERSION = '1.0.5'
 end</diff>
      <filename>lib/nokogiri/version.rb</filename>
    </modified>
    <modified>
      <diff>@@ -22,6 +22,10 @@ module Nokogiri
         end
       end
 
+      def node_cache
+        @node_cache ||= {}
+      end
+
       def to_xml
         serialize
       end</diff>
      <filename>lib/nokogiri/xml/document.rb</filename>
    </modified>
    <modified>
      <diff>@@ -25,8 +25,7 @@ module Nokogiri
       ###
       # Get the list of children for this node as a NodeSet
       def children
-        list = NodeSet.new
-        list.document = document
+        list = NodeSet.new(document)
         document.decorate(list)
 
         first = self.child
@@ -56,7 +55,7 @@ module Nokogiri
       def xpath *paths
         ns = paths.last.is_a?(Hash) ? paths.pop : {}
 
-        return NodeSet.new unless document.root
+        return NodeSet.new(document) unless document.root
 
         sets = paths.map { |path|
           ctx = XPathContext.new(self)
@@ -68,7 +67,7 @@ module Nokogiri
         }
         return sets.first if sets.length == 1
 
-        NodeSet.new do |combined|
+        NodeSet.new(document) do |combined|
           document.decorate(combined)
           sets.each do |set|
             set.each do |node|</diff>
      <filename>lib/nokogiri/xml/node.rb</filename>
    </modified>
    <modified>
      <diff>@@ -5,7 +5,8 @@ module Nokogiri
 
       attr_accessor :document
 
-      def initialize
+      def initialize document
+        @document = document
         yield self if block_given?
       end
 
@@ -50,7 +51,6 @@ module Nokogiri
       # current context.
       def unlink
         each { |node| node.unlink }
-        self.document = nil
         self
       end
       alias :remove :unlink
@@ -58,14 +58,13 @@ module Nokogiri
       ###
       # Search this document for +paths+
       def search *paths
-        sub_set = NodeSet.new
+        sub_set = NodeSet.new(document)
         document.decorate(sub_set)
         each do |node|
           node.search(*paths).each do |sub_node|
             sub_set &lt;&lt; sub_node
           end
         end
-        sub_set.document = document
         sub_set
       end
       alias :/ :search</diff>
      <filename>lib/nokogiri/xml/node_set.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,8 @@
 module Nokogiri
   module XML
     class XPath
+      attr_accessor :document
+
     end
   end
 end</diff>
      <filename>lib/nokogiri/xml/xpath.rb</filename>
    </modified>
    <modified>
      <diff>@@ -78,6 +78,17 @@ module Nokogiri
         assert @xml.document
       end
 
+      def test_singleton_methods
+        assert node_set = @xml.search('//name')
+        assert node_set.length &gt; 0
+        node = node_set.first
+        def node.test
+          'test'
+        end
+        assert node_set = @xml.search('//name')
+        assert_equal 'test', node_set.first.test
+      end
+
       def test_multiple_search
         assert node_set = @xml.search('//employee', '//name')
         employees = @xml.search('//employee')</diff>
      <filename>test/xml/test_document.rb</filename>
    </modified>
    <modified>
      <diff>@@ -54,7 +54,6 @@ module Nokogiri
           assert !node.previous_sibling
           assert !node.next_sibling
         end
-        assert !set.document
         assert_no_match(/Hello world/, xml.to_s)
       end
 
@@ -76,7 +75,7 @@ module Nokogiri
       end
 
       def test_new_nodeset
-        node_set = Nokogiri::XML::NodeSet.new
+        node_set = Nokogiri::XML::NodeSet.new(@xml)
         assert_equal(0, node_set.length)
         node = Nokogiri::XML::Node.new('form', @xml)
         node_set &lt;&lt; node</diff>
      <filename>test/xml/test_node_set.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>258045feed2b721f7d98d5090423eeb0b6944f61</id>
    </parent>
  </parents>
  <author>
    <name>Aaron Patterson</name>
    <email>aaron.patterson@gmail.com</email>
  </author>
  <url>http://github.com/tenderlove/nokogiri/commit/034a4ec02980740bb32e1c5da02d69b432945d70</url>
  <id>034a4ec02980740bb32e1c5da02d69b432945d70</id>
  <committed-date>2008-11-11T13:50:29-08:00</committed-date>
  <authored-date>2008-11-11T13:50:29-08:00</authored-date>
  <message>caching the results of NodeSet#[] on Document</message>
  <tree>dba1c69ce0c8658bf9d7c6bfbb9d320b9dfb9b19</tree>
  <committer>
    <name>Aaron Patterson</name>
    <email>aaron.patterson@gmail.com</email>
  </committer>
</commit>
