<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>merb-core/lib/merb-core/vendor/nokogiri/css.rb</filename>
    </added>
    <added>
      <filename>merb-core/lib/merb-core/vendor/nokogiri/css/generated_parser.rb</filename>
    </added>
    <added>
      <filename>merb-core/lib/merb-core/vendor/nokogiri/css/generated_tokenizer.rb</filename>
    </added>
    <added>
      <filename>merb-core/lib/merb-core/vendor/nokogiri/css/node.rb</filename>
    </added>
    <added>
      <filename>merb-core/lib/merb-core/vendor/nokogiri/css/parser.rb</filename>
    </added>
    <added>
      <filename>merb-core/lib/merb-core/vendor/nokogiri/css/parser.y</filename>
    </added>
    <added>
      <filename>merb-core/lib/merb-core/vendor/nokogiri/css/tokenizer.rb</filename>
    </added>
    <added>
      <filename>merb-core/lib/merb-core/vendor/nokogiri/css/tokenizer.rex</filename>
    </added>
    <added>
      <filename>merb-core/lib/merb-core/vendor/nokogiri/css/xpath_visitor.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,8 +1,8 @@
-begin
-  require &quot;hpricot&quot;
-  require 'merb-core/test/test_ext/hpricot'
-rescue
-end
+# begin
+#   require &quot;hpricot&quot;
+#   require 'merb-core/test/test_ext/hpricot'
+# rescue
+# end
 
 require 'merb-core/test/test_ext/object'
 require 'merb-core/test/test_ext/string'</diff>
      <filename>merb-core/lib/merb-core/test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -7,5 +7,4 @@ require &quot;merb-core/test/helpers/mock_request_helper&quot;
 require &quot;merb-core/test/helpers/route_helper&quot;
 require &quot;merb-core/test/helpers/request_helper&quot;
 require &quot;merb-core/test/helpers/multipart_request_helper&quot;
-require &quot;merb-core/test/helpers/controller_helper&quot;
-require &quot;merb-core/test/helpers/view_helper&quot;
\ No newline at end of file
+require &quot;merb-core/test/helpers/controller_helper&quot;
\ No newline at end of file</diff>
      <filename>merb-core/lib/merb-core/test/helpers.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,5 +6,4 @@ require &quot;merb-core/test/matchers/view_matchers&quot;
 require &quot;merb-core/test/matchers/request_matchers&quot;
 
 Merb::Test::ControllerHelper.send(:include, Merb::Test::Rspec::ControllerMatchers)
-Merb::Test::RouteHelper.send(:include, Merb::Test::Rspec::RouteMatchers)
-Merb::Test::ViewHelper.send(:include, Merb::Test::Rspec::ViewMatchers)
\ No newline at end of file
+Merb::Test::RouteHelper.send(:include, Merb::Test::Rspec::RouteMatchers)
\ No newline at end of file</diff>
      <filename>merb-core/lib/merb-core/test/matchers.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,11 +1,27 @@
 module Merb::Test::Rspec::ViewMatchers
+  
   class HaveXpath
-    def initialize(expected, type)
-      @expected, @type = expected, type
+    def initialize(expected, &amp;block)
+      # Require nokogiri and fall back on rexml
+      begin
+        require &quot;nokogiri&quot;
+      rescue LoadError =&gt; e
+        if require &quot;rexml/document&quot;
+          require &quot;merb-core/vendor/nokogiri/css&quot;
+          warn(&quot;Standard REXML library is slow. Please consider installing nokogiri.\nUse \&quot;sudo gem install nokogiri\&quot;&quot;)
+        end
+      end
+      
+      @expected = expected
+      @block    = block
     end
     
     def matches?(stringlike)
-      send(&quot;matches_#{@type}?&quot;, stringlike)
+      if defined?(Nokogiri::XML)
+        matches_nokogiri?(stringlike)
+      else
+        matches_rexml?(stringlike)
+      end
     end
     
     def matches_rexml?(stringlike)
@@ -17,23 +33,39 @@ module Merb::Test::Rspec::ViewMatchers
       when REXML::Node
         stringlike
       when StringIO, String
-        REXML::Document.new(stringlike).root
+        begin
+          REXML::Document.new(stringlike.to_s).root
+        rescue REXML::ParseException =&gt; e
+          if e.message.include?(&quot;second root element&quot;)
+            REXML::Document.new(&quot;&lt;fake-root-element&gt;#{stringlike}&lt;/fake-root-element&gt;&quot;).root
+          else
+            raise e
+          end
+        end
+      end
+      
+      query.all? do |q|
+        matched = REXML::XPath.match(@document, q)
+        matched.any? &amp;&amp; (!block_given? || matched.all?(&amp;@block))
       end
-      !REXML::XPath.match(@document, @expected).empty?
     end
     
-    def matches_libxml?(stringlike)
+    def matches_nokogiri?(stringlike)
       stringlike = stringlike.body.to_s if stringlike.respond_to?(:body)
       
       @document = case stringlike
-      when LibXML::XML::Document, LibXML::XML::Node
+      when Nokogiri::HTML::Document, Nokogiri::XML::NodeSet
         stringlike
       when StringIO
-        LibXML::XML::HTMLParser.string(stringlike.string).parse
+        Nokogiri::HTML(stringlike.string)
       else
-        LibXML::XML::HTMLParser.string(stringlike).parse
+        Nokogiri::HTML(stringlike.to_s)
       end
-      !@document.find(@expected).empty?
+      @document.xpath(*query).any?
+    end
+    
+    def query
+      [@expected].flatten.compact
     end
     
     # ==== Returns
@@ -49,238 +81,71 @@ module Merb::Test::Rspec::ViewMatchers
     end    
   end
   
-  class HaveSelector
-
-    # ==== Parameters
-    # expected&lt;String&gt;:: The string to look for.
-    def initialize(expected)
-      @expected = expected
-    end
-
-    # ==== Parameters
-    # stringlike&lt;Hpricot::Elem, StringIO, String&gt;:: The thing to search in.
-    #
-    # ==== Returns
-    # Boolean:: True if there was at least one match.
-    def matches?(stringlike)
-      @document = case stringlike
-      when Hpricot::Elem
-        stringlike
-      when StringIO
-        Hpricot.parse(stringlike.string)
-      else
-        Hpricot.parse(stringlike)
-      end
-      !@document.search(@expected).empty?
-    end
+  class HaveSelector &lt; HaveXpath
 
     # ==== Returns
     # String:: The failure message.
     def failure_message
       &quot;expected following text to match selector #{@expected}:\n#{@document}&quot;
     end
-
+    
     # ==== Returns
     # String:: The failure message to be displayed in negative matches.
     def negative_failure_message
       &quot;expected following text to not match selector #{@expected}:\n#{@document}&quot;
     end
-  end
-
-  class MatchTag
-
-    # ==== Parameters
-    # name&lt;~to_s&gt;:: The name of the tag to look for.
-    # attrs&lt;Hash&gt;:: Attributes to look for in the tag (see below).
-    #
-    # ==== Options (attrs)
-    # :content&lt;String&gt;:: Optional content to match.
-    def initialize(name, attrs)
-      @name, @attrs = name, attrs
-      @content = @attrs.delete(:content)
-    end
-
-    # ==== Parameters
-    # target&lt;String&gt;:: The string to look for the tag in.
-    #
-    # ==== Returns
-    # Boolean:: True if the tag matched.
-    def matches?(target)
-      @errors = []
-      unless target.include?(&quot;&lt;#{@name}&quot;)
-        @errors &lt;&lt; &quot;Expected a &lt;#{@name}&gt;, but was #{target}&quot;
-      end
-      @attrs.each do |attr, val|
-        unless target.include?(&quot;#{attr}=\&quot;#{val}\&quot;&quot;)
-          @errors &lt;&lt; &quot;Expected #{attr}=\&quot;#{val}\&quot;, but was #{target}&quot;
-        end
-      end
-      if @content
-        unless target.include?(&quot;&gt;#{@content}&lt;&quot;)
-          @errors &lt;&lt; &quot;Expected #{target} to include #{@content}&quot;
-        end
-      end
-      @errors.size == 0
+    
+    def query
+      Nokogiri::CSS::Parser.parse(*super).map { |ast| ast.to_xpath }
     end
-
+  
+  end
+  
+  class HaveTag &lt; HaveSelector
+    
     # ==== Returns
     # String:: The failure message.
     def failure_message
-      @errors[0]
+      &quot;expected following output to contain a #{tag_inspect} tag:\n#{@document}&quot;
     end
-
+    
     # ==== Returns
     # String:: The failure message to be displayed in negative matches.
     def negative_failure_message
-      &quot;Expected not to match against &lt;#{@name} #{@attrs.map{ |a,v| &quot;#{a}=\&quot;#{v}\&quot;&quot; }.join(&quot; &quot;)}&gt; tag, but it matched&quot;
-    end
-  end
-
-  class NotMatchTag
-
-    # === Parameters
-    # attrs&lt;Hash&gt;:: A set of attributes that must not be matched.
-    def initialize(attrs)
-      @attrs = attrs
-    end
-
-    # ==== Parameters
-    # target&lt;String&gt;:: The target to look for the match in.
-    #
-    # ==== Returns
-    # Boolean:: True if none of the attributes were matched.
-    def matches?(target)
-      @errors = []
-      @attrs.each do |attr, val|
-        if target.include?(&quot;#{attr}=\&quot;#{val}\&quot;&quot;)
-          @errors &lt;&lt; &quot;Should not include #{attr}=\&quot;#{val}\&quot;, but was #{target}&quot;
-        end
-      end
-      @errors.size == 0
-    end
-
-    # ==== Returns
-    # String:: The failure message.
-    def failure_message
-      @errors[0]
+      &quot;expected following output to omit a #{tag_inspect}:\n#{@document}&quot;
     end
-  end
-  
-  class HasTag
     
-    attr_accessor :outer_has_tag, :inner_has_tag
-
-    # ==== Parameters
-    # tag&lt;~to_s&gt;:: The tag to look for.
-    # attributes&lt;Hash&gt;:: Attributes for the tag (see below).
-    def initialize(tag, attributes = {}, &amp;blk)
-      @tag, @attributes = tag, attributes
-      @id, @class = @attributes.delete(:id), @attributes.delete(:class)
-      @blk = blk
-    end
-
-    # ==== Parameters
-    # stringlike&lt;Hpricot::Elem, StringIO, String&gt;:: The thing to search in.
-    # &amp;blk:: An optional block for searching in child elements using with_tag.
-    #
-    # ==== Returns
-    # Boolean:: True if there was at least one match.
-    def matches?(stringlike, &amp;blk)
-      @document = case stringlike
-      when Hpricot::Elem
-        stringlike
-      when StringIO
-        Hpricot.parse(stringlike.string)
-      else
-        Hpricot.parse(stringlike)
+    def tag_inspect
+      options = @expected.last.dup
+      content = options.delete(:content)
+      
+      html = &quot;&lt;#{@expected.first}&quot;
+      options.each do |k,v|
+        html &lt;&lt; &quot; #{k}='#{v}'&quot;
       end
       
-      @blk = blk unless blk.nil?
-
-      unless @blk.nil?
-        !@document.search(selector).select do |ele|
-          begin
-            @blk.call ele
-            true
-          rescue Spec::Expectations::ExpectationNotMetError
-            @error_message = &quot;#{tag_for_error}:\n&quot; + $!.message
-            false
-          end
-        end.empty?
+      if content
+        html &lt;&lt; &quot;&gt;#{content}&lt;/#{@expected.first}&gt;&quot;
       else
-        !@document.search(selector).empty?
+        html &lt;&lt; &quot;/&gt;&quot;
       end
-    end
-
-    # ==== Returns
-    # String:: The complete selector for element queries.
-    def selector
-      @selector = @outer_has_tag ? @outer_has_tag.selector : ''
-
-      @selector &lt;&lt; &quot;//#{@tag}#{id_selector}#{class_selector}&quot;
-      @selector &lt;&lt; @attributes.map{|a, v| &quot;[@#{a}=\&quot;#{v}\&quot;]&quot;}.join
-    end
-
-    # ==== Returns
-    # String:: ID selector for use in element queries.
-    def id_selector
-      &quot;##{@id}&quot; if @id
-    end
-
-    # ==== Returns
-    # String:: Class selector for use in element queries.
-    def class_selector
-      &quot;.#{@class}&quot; if @class
-    end
-
-    # ==== Returns
-    # String:: The failure message.
-    def failure_message
-      @error_message || &quot;expected following output to contain a #{tag_for_error} tag:\n#{@document}&quot;
-    end
-
-    # ==== Returns
-    # String:: The failure message to be displayed in negative matches.
-    def negative_failure_message
-      @error_message || &quot;expected following output to omit a #{tag_for_error} tag:\n#{@document}&quot;
+      
+      html
     end
     
-    # ==== Returns
-    # String:: The tag used in failure messages.
-    def tag_for_error
-      result = &quot;#{@tag}#{id_for_error}#{class_for_error}#{attributes_for_error}&quot;
-      inner_has_tag ? result &lt;&lt; &quot; &gt; #{inner_has_tag.tag_for_error}&quot; : result
-    end
-
-    # ==== Returns
-    # String:: ID for the error tag.
-    def id_for_error
-      &quot;##{@id}&quot; unless @id.nil?
-    end
-
-    # ==== Returns
-    # String:: Class for the error tag.
-    def class_for_error
-      &quot;.#{@class}&quot; unless @class.nil?
-    end
-
-    # ==== Returns
-    # String:: Class for the error tag.
-    def attributes_for_error
-      @attributes.map{|a,v| &quot;[#{a}=\&quot;#{v}\&quot;]&quot;}.join
-    end
-
-    # Search for a child tag within a have_tag block.
-    #
-    # ==== Parameters
-    # tag&lt;~to_s&gt;:: The tag to look for.
-    # attributes&lt;Hash&gt;:: Attributes for the tag (see below).
-    def with_tag(name, attrs={})
-      @inner_has_tag = HasTag.new(name, attrs)
-      @inner_has_tag.outer_has_tag = self
+    def query
+      options  = @expected.last.dup
+      selector = @expected.first.to_s
+      
+      selector &lt;&lt; &quot;:contains('#{options.delete(:content)}')&quot; if options[:content]
       
-      @inner_has_tag
+      options.each do |key, value|
+        selector &lt;&lt; &quot;[#{key}='#{value}']&quot;
+      end
+      
+      Nokogiri::CSS::Parser.parse(selector).map { |ast| ast.to_xpath }
     end
+    
   end
 
   class HasContent
@@ -289,6 +154,7 @@ module Merb::Test::Rspec::ViewMatchers
     end
 
     def matches?(element)
+      element = element.body.to_s if element.respond_to?(:body)
       @element = element
       
       case @content
@@ -320,83 +186,45 @@ module Merb::Test::Rspec::ViewMatchers
       end
     end
   end
-  
-  # ==== Parameters
-  # name&lt;~to_s&gt;:: The name of the tag to look for.
-  # attrs&lt;Hash&gt;:: Attributes to look for in the tag (see below).
-  #
-  # ==== Options (attrs)
-  # :content&lt;String&gt;:: Optional content to match.
-  #
-  # ==== Returns
-  # MatchTag:: A new match tag matcher.
-  def match_tag(name, attrs={})
-    MatchTag.new(name, attrs)
-  end
 
-  # ==== Parameters
-  # attrs&lt;Hash&gt;:: A set of attributes that must not be matched.
+  # Matches HTML content against a CSS 3 selector.
   #
-  # ==== Returns
-  # NotMatchTag:: A new not match tag matcher.
-  def not_match_tag(attrs)
-    NotMatchTag.new(attrs)
-  end
-
   # ==== Parameters
-  # expected&lt;String&gt;:: The string to look for.
+  # expected&lt;String&gt;:: The CSS selector to look for.
   #
   # ==== Returns
   # HaveSelector:: A new have selector matcher.
+  # ---
+  # @api public
   def have_selector(expected)
     HaveSelector.new(expected)
   end
   alias_method :match_selector, :have_selector
 
-  def have_xpath(expected)
-    begin
-      require &quot;libxml&quot;
-      type = &quot;libxml&quot;
-    rescue LoadError =&gt; e
-      if require &quot;rexml/document&quot; # show warning only once
-        warn(&lt;&lt;-WARN_TEXT)
-Standard REXML library is slow. Please consider to install libxml-ruby.
-Use &quot;sudo gem install libxml-ruby&quot;
-WARN_TEXT
-      end
-      type = &quot;rexml&quot;
-    end
-    HaveXpath.new(expected, type)
-  end
-  alias_method :match_xpath, :have_xpath
-
-  # RSpec matcher to test for the presence of tags.
+  # Matches HTML content against an XPath query
   #
   # ==== Parameters
-  # tag&lt;~to_s&gt;:: The name of the tag.
-  # attributes&lt;Hash&gt;:: Tag attributes.
+  # expected&lt;String&gt;:: The XPath query to look for.
   #
   # ==== Returns
-  # HasTag:: A new has tag matcher.
-  #
-  # ==== Examples
-  #   # Check for &lt;div&gt;
-  #   body.should have_tag(&quot;div&quot;)
-  #
-  #   # Check for &lt;span id=&quot;notice&quot;&gt;
-  #   body.should have_tag(&quot;span&quot;, :id =&gt; :notice)
-  #
-  #   # Check for &lt;h1 id=&quot;foo&quot; class=&quot;bar&quot;&gt;
-  #   body.should have_tag(:h2, :class =&gt; &quot;bar&quot;, :id =&gt; &quot;foo&quot;)
-  #
-  #   # Check for &lt;div attr=&quot;val&quot;&gt;
-  #   body.should have_tag(:div, :attr =&gt; :val)
-  def have_tag(tag, attributes = {}, &amp;blk)
-    HasTag.new(tag, attributes, &amp;blk)
+  # HaveXpath:: A new have xpath matcher.
+  # ---
+  # @api public
+  def have_xpath(expected)
+    HaveXpath.new(expected)
   end
-
-  alias_method :with_tag, :have_tag
+  alias_method :match_xpath, :have_xpath
+  
+  def have_tag(name, attributes = {})
+    HaveTag.new([name, attributes])
+  end
+  alias_method :match_tag, :have_tag
   
+  # Matches the contents of an HTML document with
+  # whatever string is supplied
+  #
+  # ---
+  # @api public
   def contain(content)
     HasContent.new(content)
   end</diff>
      <filename>merb-core/lib/merb-core/test/matchers/view_matchers.rb</filename>
    </modified>
    <modified>
      <diff>@@ -42,7 +42,6 @@ module Merb
     class ExampleGroup &lt; Spec::Example::ExampleGroup
 
       include ::Merb::Test::Matchers
-      include ::Merb::Test::ViewHelper
       include ::Merb::Test::RouteHelper
       include ::Merb::Test::ControllerHelper
 </diff>
      <filename>merb-core/lib/merb-core/test/test_ext/rspec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -5,6 +5,10 @@ module Merb::Test
       &quot;Method - #{request.method.to_s.upcase}&quot;
     end
     
+    def document
+      '&lt;html&gt;&lt;body&gt;&lt;div id=&quot;out&quot;&gt;&lt;div class=&quot;in&quot;&gt;Hello&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;'
+    end
+    
     def counter
       value = (cookies[:counter] || 0).to_i + 1
       cookies[:counter] = value</diff>
      <filename>merb-core/spec/public/test/controllers/request_controller.rb</filename>
    </modified>
    <modified>
      <diff>@@ -21,6 +21,18 @@ describe Merb::Test::RequestHelper do
     request(&quot;/method&quot;).should have_body(&quot;Method - GET&quot;)
   end
   
+  it &quot;should work with have_selector&quot; do
+    request(&quot;/document&quot;).should have_selector(&quot;div div&quot;)
+  end
+  
+  it &quot;should work with have_xpath&quot; do
+    request(&quot;/document&quot;).should have_xpath(&quot;//div/div&quot;)
+  end
+  
+  it &quot;should work with have_content&quot; do
+    request(&quot;/method&quot;).should contain(&quot;Method&quot;)
+  end
+  
   it &quot;should persist cookies across sequential cookie setting requests&quot; do
     request(&quot;/counter&quot;).should have_body(&quot;1&quot;)
     request(&quot;/counter&quot;).should have_body(&quot;2&quot;)</diff>
      <filename>merb-core/spec/public/test/request_helper_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -4,7 +4,6 @@ require &quot;merb-core/test&quot;
 Merb.start :environment =&gt; 'test', :log_level =&gt; :fatal
 
 describe Merb::Test::Rspec::ViewMatchers do
-  include Merb::Test::ViewHelper
   
   before(:each) do
     @body = &lt;&lt;-EOF
@@ -14,128 +13,50 @@ describe Merb::Test::Rspec::ViewMatchers do
     EOF
   end
   
-  describe &quot;#match_tag&quot; do
-    it &quot;should work with a HasContent matcher in the block&quot; do
-      @body.should have_tag(:div) {|d| d.should_not contain(&quot;merb&quot;)}
+  describe &quot;#have_selector&quot; do
+    
+    it &quot;should be able to match a CSS selector&quot; do
+      @body.should have_selector(&quot;div&quot;)
+    end
+    
+    it &quot;should not match a CSS selector that does not exist&quot; do
+      @body.should_not have_selector(&quot;p&quot;)
     end
     
-    it &quot;should work with a 'with_tag' chain&quot; do
-      @body.should have_tag(:div, :id =&gt; :main).with_tag(:div, :class =&gt; 'inner')
+    it &quot;should be able to loop over all the matched elements&quot; do
+      @body.should have_selector(&quot;div&quot;) { |node| node.name.should == &quot;div&quot; }
     end
     
-    it &quot;should work with a block before a with_tag&quot; do
-      @body.should have_tag(:div, :id =&gt; :main) {|d| d.should_not contain(&quot;merb&quot;)}.with_tag(:div, :class =&gt; 'inner')
+    it &quot;should not match of any of the matchers in the block fail&quot; do
+      lambda {
+        @body.should_not have_selector(&quot;div&quot;) { |node| node.name.should == &quot;p&quot; }
+      }.should raise_error(Spec::Expectations::ExpectationNotMetError)
     end
+    
   end
-
-  module Merb::Test::Rspec::ViewMatchers
   
-    describe HasTag do
-      describe &quot;#matches?&quot; do
-        before(:each) do
-          @document = stub(:document)
-          Hpricot.should_receive(:parse).and_return @document
-        end
-      
-        it &quot;should pass all found elements to the block&quot; do
-          @block_called = false
-        
-          @document.should_receive(:search).and_return [&quot;&quot;]
-          HasTag.new(&quot;tag&quot;).matches?(&quot;&quot;) {|e| e.should == &quot;&quot; }
-        end
-      
-        it 'should intercept errors raised in the block' do
-          @document.should_receive(:search).and_return [&quot;&quot;]
-          lambda {
-            HasTag.new(&quot;tag&quot;).matches?(&quot;&quot;) {|e| true.should be_false }
-          }.should_not raise_error(Spec::Expectations::ExpectationNotMetError)
-        end
-
-        it 'should raise ExpectationNotMetError when there are no matched elements' do
-          @document.should_receive(:search).and_return [&quot;&quot;]
-          lambda {
-            @document.should have_tag(:tag) {|e| true.should be_false }
-          }.should raise_error(Spec::Expectations::ExpectationNotMetError, &quot;tag:\nexpected false, got true&quot;)
-        end
-
-        #part of bugfix for #329
-        it 'should not raise error if block for first of matched elements by xpath expression fails' do
-          @document.should_receive(:search).and_return [&quot;a&quot;, &quot;b&quot;]
-          lambda {
-            @document.should have_tag(:tag) { |tag| tag.should == &quot;b&quot; }
-          }.should_not raise_error(Spec::Expectations::ExpectationNotMetError)
-        end
-      end
+  describe &quot;#have_tag&quot; do
     
-      describe &quot;#with_tag&quot; do
-        it &quot;should set @outer_has_tag&quot; do
-          outer = HasTag.new(&quot;outer&quot;)
-          inner = outer.with_tag(&quot;inner&quot;)
-        
-          inner.selector.should include(outer.selector)
-        end
-      end
+    it &quot;should be able to match a tag&quot; do
+      @body.should have_tag(&quot;div&quot;)
+    end
     
-      describe &quot;#selector&quot; do
-        it &quot;should always start with \/\/&quot; do
-          HasTag.new(&quot;tag&quot;).selector.should =~ /^\/\//
-        end
-      
-        it &quot;should use @tag for the element&quot; do
-          HasTag.new(&quot;tag&quot;).selector.should include(&quot;tag&quot;)
-        end
-      
-        it &quot;should use dot notation for the class&quot; do
-          HasTag.new(&quot;tag&quot;, :class =&gt; &quot;class&quot;).selector.should include(&quot;tag.class&quot;)
-        end
-      
-        it &quot;should use pound(#) notation for the id&quot; do
-          HasTag.new(&quot;tag&quot;, :id =&gt; &quot;id&quot;).selector.should include(&quot;tag#id&quot;)
-        end
-      
-        it &quot;should include any custom attributes&quot; do
-          HasTag.new(&quot;tag&quot;, :random =&gt; :attribute).selector.should include(&quot;[@random=\&quot;attribute\&quot;]&quot;)
-        end
-      
-        it &quot;should not include the class as a custom attribute&quot; do
-          HasTag.new(&quot;tag&quot;, :class =&gt; :my_class, :rand =&gt; :attr).selector.should_not include(&quot;[@class=\&quot;my_class\&quot;]&quot;)
-        end
-      
-        it &quot;should not include the id as a custom attribute&quot; do
-          HasTag.new(&quot;tag&quot;, :id =&gt; :my_id, :rand =&gt; :attr).selector.should_not include(&quot;[@id=\&quot;my_id\&quot;]&quot;)
-        end
-      end
+    it &quot;should not match the tag when it should not match&quot; do
+      @body.should_not have_tag(&quot;p&quot;)
+    end
     
-      describe &quot;#failure_message&quot; do
-        it &quot;should include the tag name&quot; do
-          HasTag.new(&quot;anytag&quot;).failure_message.should include(&quot;anytag&quot;)
-        end
-      
-        it &quot;should include the tag's id&quot; do
-          HasTag.new(&quot;div&quot;, :id =&gt; :spacer).failure_message.should include(&quot;div#spacer&quot;)
-        end
-      
-        it &quot;should include the tag's class&quot; do
-          HasTag.new(&quot;div&quot;, :class =&gt; :header).failure_message.should include(&quot;div.header&quot;)
-        end
-      
-        it &quot;should include the tag's custom attributes&quot; do
-          HasTag.new(&quot;h1&quot;, :attr =&gt; :val, :foo =&gt; :bar).failure_message.should include(&quot;attr=\&quot;val\&quot;&quot;)
-          HasTag.new(&quot;h1&quot;, :attr =&gt; :val, :foo =&gt; :bar).failure_message.should include(&quot;foo=\&quot;bar\&quot;&quot;)
-        end
-      end
+    it &quot;should be able to specify the content of the tag&quot; do
+      @body.should have_tag(&quot;div&quot;, :content  =&gt; &quot;hello, world!&quot;)
+    end
     
-      describe &quot;id, class, and attributes for error messages&quot; do
-        it &quot;should have '.classifier' in class_for_error&quot; do
-          HasTag.new(&quot;tag&quot;, :class =&gt; &quot;classifier&quot;).class_for_error.should include(&quot;.classifier&quot;)
-        end
-      
-        it &quot;should have '#identifier' in id_for_error&quot; do
-          HasTag.new(&quot;tag&quot;, :id =&gt; &quot;identifier&quot;).id_for_error.should include(&quot;#identifier&quot;)
-        end
-      end
+    it &quot;should be able to specify the attributes of the tag&quot; do
+      @body.should have_tag(&quot;div&quot;, :class =&gt; &quot;inner&quot;)
     end
     
+  end
+
+  module Merb::Test::Rspec::ViewMatchers
+   
     describe HasContent do
       before(:each) do
         @element = stub(:element)</diff>
      <filename>merb-core/spec/public/test/view_matchers_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,4 @@
-&lt;%= form_for @obj do %&gt;
+&lt;%= form_for @obj, :action =&gt; &quot;/&quot; do %&gt;
   &lt;%= check_box(:baz) %&gt;
   &lt;%= check_box(:bat) %&gt;
 &lt;% end =%&gt;</diff>
      <filename>merb-helpers/spec/fixture/app/views/bound_check_box_specs/basic.html.erb</filename>
    </modified>
    <modified>
      <diff>@@ -1,3 +1,3 @@
-&lt;%= form_for @model do %&gt;
+&lt;%= form_for @model, :action =&gt; &quot;/&quot; do %&gt;
   &lt;%= hidden_field(:foo, :bar =&gt;&quot;7&quot;) %&gt;
 &lt;% end =%&gt;</diff>
      <filename>merb-helpers/spec/fixture/app/views/bound_hidden_field_specs/hidden_error.html.erb</filename>
    </modified>
    <modified>
      <diff>@@ -1,3 +1,3 @@
-&lt;%= form_for @obj do %&gt;
+&lt;%= form_for @obj, :action =&gt; &quot;/&quot; do %&gt;
   &lt;%= password_field(:foo, :bar =&gt; &quot;7&quot;, :label =&gt; &quot;LABEL&quot;) %&gt;
 &lt;% end =%&gt;</diff>
      <filename>merb-helpers/spec/fixture/app/views/bound_password_field_specs/basic.html.erb</filename>
    </modified>
    <modified>
      <diff>@@ -1,3 +1,3 @@
-&lt;%= form_for @obj do %&gt;
+&lt;%= form_for @obj, :action =&gt; &quot;/&quot; do %&gt;
 &lt;%= radio_button(:foo, :bar =&gt; &quot;7&quot;, :label =&gt; &quot;LABEL&quot;) %&gt;
 &lt;% end =%&gt;</diff>
      <filename>merb-helpers/spec/fixture/app/views/bound_radio_button_specs/basic.html.erb</filename>
    </modified>
    <modified>
      <diff>@@ -1,3 +1,3 @@
-&lt;%= form_for @obj do %&gt;
+&lt;%= form_for @obj, :action =&gt; &quot;/&quot; do %&gt;
   &lt;%= text_field :foo, :bar =&gt; &quot;7&quot;, :label =&gt; &quot;LABEL&quot; %&gt;
 &lt;% end =%&gt;</diff>
      <filename>merb-helpers/spec/fixture/app/views/bound_text_field_specs/basic.html.erb</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
   &lt;head&gt;
     &lt;title&gt;Fresh Merb App&lt;/title&gt;
     &lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;
-    &lt;link rel=&quot;stylesheet&quot; href=&quot;/stylesheets/master.css&quot; type=&quot;text/css&quot; media=&quot;screen&quot; charset=&quot;utf-8&quot;&gt;
+    &lt;link rel=&quot;stylesheet&quot; href=&quot;/stylesheets/master.css&quot; type=&quot;text/css&quot; media=&quot;screen&quot; charset=&quot;utf-8&quot;/&gt;
   &lt;/head&gt;
   &lt;body&gt;
     &lt;%= catch_content :for_layout %&gt;</diff>
      <filename>merb-helpers/spec/fixture/app/views/layout/application.html.erb</filename>
    </modified>
    <modified>
      <diff>@@ -120,25 +120,25 @@ describe &quot;form&quot; do
 
   it &quot;should use the post method by default&quot; do
     ret = @c.render(:post_by_default)
-    ret.should match_tag(:form, :method =&gt; &quot;post&quot;)
+    ret.should have_selector(&quot;form[method=post]&quot;)
     ret.should include(&quot;CONTENT&quot;)
   end
 
   it &quot;should use the get method if set&quot; do
     ret = @c.render(:get_if_set)
-    ret.should match_tag(:form, :method =&gt; &quot;get&quot;)
+    ret.should have_selector(&quot;form[method=get]&quot;)
   end
   
   it &quot;should fake out the put method if set&quot; do
     ret = @c.render(:fake_put_if_set)
-    ret.should match_tag(:form, :method =&gt; &quot;post&quot;)
-    ret.should match_tag(:input, :type =&gt; &quot;hidden&quot;, :name =&gt; &quot;_method&quot;, :value =&gt; &quot;put&quot;)
+    ret.should have_selector(&quot;form[method=post]&quot;)
+    ret.should have_selector(&quot;input[type=hidden][name=_method][value=put]&quot;)
   end
   
   it &quot;should fake out the delete method if set&quot; do
     ret = @c.render(:fake_delete_if_set)
-    ret.should match_tag(:form, :method =&gt; &quot;post&quot;)
-    ret.should match_tag(:input, :type =&gt; &quot;hidden&quot;, :name =&gt; &quot;_method&quot;, :value =&gt; &quot;delete&quot;)
+    ret.should have_selector(&quot;form[method=post]&quot;)
+    ret.should have_selector(&quot;input[type=hidden][name=_method][value=delete]&quot;)
   end
   
   # TODO: Why is this required?
@@ -153,14 +153,14 @@ describe &quot;form&quot; do
   # end
   
   it &quot;should take create a form&quot; do
-    ret = @c.render(:create_a_form)  
-    ret.should match_tag(:form, :action =&gt; &quot;foo&quot;, :method =&gt; &quot;post&quot;)
+    ret = @c.render(:create_a_form)
+    ret.should have_selector(&quot;form[action=foo][method=post]&quot;)
     ret.should include(&quot;Hello&quot;)
   end
   
   it &quot;should set a form to be multipart&quot; do
     ret = @c.render(:create_a_multipart_form)
-    ret.should match_tag( :form, :action =&gt; &quot;foo&quot;, :method =&gt; &quot;post&quot;, :enctype =&gt; &quot;multipart/form-data&quot;)
+    ret.should have_selector(&quot;form[action=foo][method=post][enctype='multipart/form-data']&quot;)
     ret.should include(&quot;CONTENT&quot;)
   end
 end
@@ -175,22 +175,22 @@ describe &quot;form_for&quot; do
 
   it &quot;should wrap the contents in a form tag&quot; do
     form = @c.render :basic
-    form.should match_tag(:form, :method =&gt; &quot;post&quot;)
-    form.should match_tag(:input, :type =&gt; &quot;hidden&quot;, :value =&gt; &quot;put&quot;, :name =&gt; &quot;_method&quot;)
+    form.should have_selector(&quot;form[method=post]&quot;)
+    form.should have_selector(&quot;input[type=hidden][value=put][name=_method]&quot;)
   end
 
   it &quot;should set the method to post be default&quot; do
     new_fake_model = FakeModel2.new
     @c.instance_variable_set(:@obj, new_fake_model)
     form = @c.render :basic
-    form.should match_tag(:form, :method =&gt; &quot;post&quot;)
-    form.should_not match_tag(:input, :type =&gt; &quot;hidden&quot;, :name =&gt; &quot;_method&quot;)
+    form.should have_selector(&quot;form[method=post]&quot;)
+    form.should_not have_selector(&quot;input[type=hidden][name=_method]&quot;)
   end
 
   it &quot;should support PUT if the object passed in is not a new_record? via a hidden field&quot; do
     form = @c.render :basic
-    form.should match_tag(:form, :method =&gt; &quot;post&quot;)
-    form.should match_tag(:input, :type =&gt; &quot;hidden&quot;, :value =&gt; &quot;put&quot;, :name =&gt; &quot;_method&quot;)
+    form.should have_selector(&quot;form[method=post]&quot;)
+    form.should have_selector(&quot;input[type=hidden][value=put][name=_method]&quot;)
   end
 
 end
@@ -206,25 +206,25 @@ describe &quot;fields_for&quot; do
 
   it &quot;should dump the contents in the context of the object&quot; do
     r = @c.render :basic
-    r.should match_tag(:input, :type =&gt; &quot;text&quot;, :value =&gt; &quot;foowee&quot;)
+    r.should have_selector(&quot;input[type=text][value=foowee]&quot;)
   end
 
   it &quot;should be able to modify the context midstream&quot; do
     @c.instance_variable_set(:@obj2, FakeModel2.new)
     r = @c.render :midstream
-    r.should match_tag(:input, :type =&gt; &quot;text&quot;, :value =&gt; &quot;foowee&quot;)
-    r.should match_tag(:input, :name =&gt; &quot;fake_model2[foo]&quot;, :type =&gt; &quot;text&quot;, :value =&gt; &quot;foowee2&quot;)
+    r.should have_selector(&quot;input[type=text][value=foowee]&quot;)
+    r.should have_selector(&quot;input[name='fake_model2[foo]'][type=text][value=foowee2]&quot;)
   end
 
   it &quot;should handle an explicit nil attribute&quot; do
     r = @c.render :nil
-    r.should match_tag(:input, :name =&gt; &quot;fake_model[foo]&quot;, :value =&gt; &quot;foowee&quot;, :type =&gt; &quot;text&quot;)
+    r.should have_selector(&quot;input[name='fake_model[foo]'][value=foowee][type=text]&quot;)
   end
 
   it &quot;should pass context back to the old object after exiting block&quot; do
     @c.instance_variable_set(:@obj2, FakeModel2.new)
     r = @c.render :midstream
-    r.should match_tag(:input, :id =&gt; &quot;fake_model_foo&quot;, :name =&gt; &quot;fake_model[foo]&quot;, :type =&gt; &quot;text&quot;, :extra =&gt; &quot;true&quot;)
+    r.should have_selector(&quot;input[id=fake_model_foo][name='fake_model[foo]'][type=text][extra=true]&quot;)
   end
 end
 
@@ -236,7 +236,7 @@ describe &quot;text_field&quot; do
 
   it &quot;should return a basic text field based on the values passed in&quot; do
     r = @c.render :basic
-    r.should match_tag( :input, :type =&gt; &quot;text&quot;, :name =&gt; &quot;foo&quot;, :value =&gt; &quot;bar&quot;)
+    r.should have_selector(&quot;input[type=text][name=foo][value=bar]&quot;)
   end
 
   it &quot;should provide an additional label tag if the :label option is passed in&quot; do
@@ -251,7 +251,7 @@ describe &quot;text_field&quot; do
   
   it &quot;should be disabled if :disabled =&gt; true is passed in&quot; do
     r = @c.render :disabled
-    r.should match_tag(:input, :type =&gt; &quot;text&quot;, :disabled =&gt; &quot;disabled&quot;)
+    r.should have_selector(&quot;input[type=text][disabled=disabled]&quot;)
   end
 
   it &quot;should provide an additional label tag if the :label option is passed in as a hash&quot; do
@@ -270,24 +270,23 @@ describe &quot;bound_text_field&quot; do
 
   it &quot;should take a string object and return a useful text control&quot; do
     r = @c.render :basic
-    r.should match_tag(:input, :type =&gt; &quot;text&quot;, :name =&gt; &quot;fake_model[foo]&quot;, :value =&gt; &quot;foowee&quot;)
+    r.should have_selector(&quot;input[type=text][name='fake_model[foo]'][value=foowee]&quot;)
   end
 
   it &quot;should take additional attributes and use them&quot; do
     r = @c.render :basic
-    r.should match_tag(:input, :type =&gt; &quot;text&quot;, :name =&gt; &quot;fake_model[foo]&quot;, :value =&gt; &quot;foowee&quot;, :bar =&gt; &quot;7&quot;)
+    r.should have_selector(&quot;input[type=text][name='fake_model[foo]'][value=foowee][bar='7']&quot;)
   end
 
   it &quot;should provide an additional label tag if the :label option is passed in&quot; do
     form = @c.render :basic
     form.should match(/&lt;label.*&gt;LABEL&lt;\/label&gt;&lt;input/)
-    res = form.scan(/&lt;[^&gt;]*&gt;/)
-    res[2].should_not match_tag(:input, :label =&gt; &quot;LABEL&quot;)
+    form.should_not have_selector(&quot;input[label=LABEL]&quot;)
   end
 
   it &quot;should not errorify the field for a new object&quot; do
     r = @c.render :basic
-    r.should_not match_tag(:input, :type =&gt; &quot;text&quot;, :name =&gt; &quot;fake_model[foo]&quot;, :class =&gt; &quot;error&quot;)
+    r.should_not have_selector(&quot;input[type=text][name='fake_model[foo]'][class=error]&quot;)
   end
 
   it &quot;should errorify a field for a model with errors&quot; do
@@ -301,7 +300,7 @@ describe &quot;bound_text_field&quot; do
     model.stub!(:errors).and_return(errors)
     @c.instance_variable_set(:@obj, model)
     r = @c.render :basic
-    r.should match_tag(:input, :class =&gt; &quot;error text&quot;)
+    r.should have_selector(&quot;input[class='error text']&quot;)
   end
 end
 
@@ -314,24 +313,23 @@ describe &quot;bound_radio_button&quot; do
 
   it &quot;should take a string object and return a useful text control&quot; do
     r = @c.render :basic
-    r.should match_tag(:input, :type =&gt; &quot;radio&quot;, :name =&gt; &quot;fake_model[foo]&quot;, :value =&gt; &quot;foowee&quot;)
+    r.should have_selector(&quot;input[type=radio][name='fake_model[foo]'][value=foowee]&quot;)
   end
 
   it &quot;should take additional attributes and use them&quot; do
     r = @c.render :basic
-    r.should match_tag(:input, :type =&gt; &quot;radio&quot;, :name =&gt; &quot;fake_model[foo]&quot;, :value =&gt; &quot;foowee&quot;, :bar =&gt; &quot;7&quot;)
+    r.should have_selector(&quot;input[type=radio][name='fake_model[foo]'][value=foowee][bar='7']&quot;)
   end
 
   it &quot;should provide an additional label tag if the :label option is passed in&quot; do
     form = @c.render :basic
-    form.should match(/&lt;input.*&gt;&lt;label.*&gt;LABEL&lt;\/label&gt;/)
-    res = form.scan(/&lt;[^&gt;]*&gt;/)
-    res[2].should_not match_tag(:input, :label =&gt; &quot;LABEL&quot;)
+    form.should have_selector(&quot;input + label:contains('LABEL')&quot;)
+    form.should_not have_selector(&quot;input[label]&quot;)
   end
 
   it &quot;should not errorify the field for a new object&quot; do
     r = @c.render :basic
-    r.should_not match_tag(:input, :type =&gt; &quot;radio&quot;, :name =&gt; &quot;fake_model[foo]&quot;, :class =&gt; &quot;error&quot;)
+    r.should_not have_selector(&quot;input[type=radio][name='fake_model[foo]'][class=error]&quot;)
   end
 
   it &quot;should errorify a field for a model with errors&quot; do
@@ -345,7 +343,7 @@ describe &quot;bound_radio_button&quot; do
     model.stub!(:errors).and_return(errors)
     @c.instance_variable_set(:@obj, model)
     r = @c.render :basic
-    r.should match_tag(:input, :class =&gt; &quot;error radio&quot;)
+    r.should have_selector(&quot;input[class='error radio']&quot;)
   end
 end
 
@@ -357,12 +355,12 @@ describe &quot;password_field&quot; do
 
   it &quot;should return a basic password field, but omit the value&quot; do
     r = @c.render :basic
-    r.should match_tag(:input, :type =&gt; &quot;password&quot;, :name =&gt; &quot;foo&quot;)
+    r.should have_selector(&quot;input[type=password][name=foo]&quot;)
   end
 
   it &quot;should provide an additional label tag if the :label option is passed in&quot; do
     r = @c.render :basic
-    r.should match(/&lt;label.*&gt;LABEL&lt;\/label&gt;/)
+    r.should have_selector(&quot;label:contains('LABEL')&quot;)
   end
   
   it &quot;should be disabled if :disabled =&gt; true is passed in&quot; do
@@ -392,8 +390,7 @@ describe &quot;bound_password_field&quot; do
   it &quot;should provide an additional label tag if the :label option is passed in&quot; do
     r = @c.render :basic
     r.should match(/&lt;label.*&gt;LABEL&lt;\/label&gt;&lt;input/)
-    res = r.scan(/&lt;[^&gt;]*&gt;/)
-    res[2].should_not match_tag(:input, :label =&gt; &quot;LABEL&quot;)
+    r.should_not match_tag(:input, :label =&gt; &quot;LABEL&quot;)
   end
 
   it &quot;should not errorify the field for a new object&quot; do
@@ -512,7 +509,7 @@ describe &quot;bound_check_box&quot; do
   it &quot;should take a string and return a useful checkbox control&quot; do
     r = @c.render :basic  
     r.should match_tag(:input, :type =&gt;&quot;checkbox&quot;, :name =&gt; &quot;fake_model[baz]&quot;, :class =&gt; &quot;checkbox&quot;, :value =&gt; &quot;1&quot;, :checked =&gt; &quot;checked&quot;, :id =&gt; &quot;fake_model_baz&quot;)
-    r.should match_tag(:input, :type =&gt;&quot;checkbox&quot;, :name =&gt; &quot;fake_model[bat]&quot;, :class =&gt; &quot;checkbox&quot;, :value =&gt; &quot;0&quot;)
+    r.should match_tag(:input, :type =&gt;&quot;hidden&quot;,   :name =&gt; &quot;fake_model[baz]&quot;, :value =&gt; &quot;0&quot;)
   end
 
   it &quot;should raise an error if you try to use :value&quot; do
@@ -529,25 +526,27 @@ describe &quot;bound_check_box&quot; do
                                               :value   =&gt; &quot;1&quot;,
                                               :checked =&gt; &quot;checked&quot;,
                                               :id      =&gt; &quot;fake_dm_model_baz&quot;)
-    r.should match_tag(:input, :type =&gt;&quot;checkbox&quot;, :name =&gt; &quot;fake_dm_model[bat]&quot;, :class =&gt; &quot;checkbox&quot;, :value =&gt; &quot;0&quot;)
+    
+    r.should match_tag(:input, :type =&gt;&quot;hidden&quot;,   :name =&gt; &quot;fake_dm_model[bat]&quot;, :value =&gt; &quot;0&quot;)                                          
+    r.should match_tag(:input, :type =&gt;&quot;checkbox&quot;, :name =&gt; &quot;fake_dm_model[bat]&quot;, :class =&gt; &quot;checkbox&quot;, :value =&gt; &quot;1&quot;)
   end
 
   it &quot;should allow a user to set the :off value&quot; do
     r = @c.render :on_and_off
-    r.should match_tag(:input, :type =&gt;&quot;checkbox&quot;, :name =&gt; &quot;fake_model[bat]&quot;, :class =&gt; &quot;checkbox&quot;, :value =&gt; &quot;off&quot;)
+    r.should match_tag(:input, :type =&gt;&quot;hidden&quot;,   :name =&gt; &quot;fake_model[bat]&quot;, :value =&gt; &quot;off&quot;)
+    r.should match_tag(:input, :type =&gt;&quot;checkbox&quot;, :name =&gt; &quot;fake_model[bat]&quot;, :class =&gt; &quot;checkbox&quot;, :value =&gt; &quot;on&quot;)
   end
 
   it &quot;should render controls with errors if their attribute contains an error&quot; do
     r = @c.render :errors  
     r.should match_tag(:input, :type =&gt;&quot;checkbox&quot;, :name =&gt; &quot;fake_model[bazbad]&quot;, :class =&gt; &quot;error checkbox&quot;, :value =&gt; &quot;1&quot;, :checked =&gt; &quot;checked&quot;)
-    r.should match_tag(:input, :type =&gt;&quot;checkbox&quot;, :name =&gt; &quot;fake_model[batbad]&quot;, :class =&gt; &quot;error checkbox&quot;, :value =&gt; &quot;0&quot;)
+    r.should match_tag(:input, :type =&gt;&quot;hidden&quot;,   :name =&gt; &quot;fake_model[batbad]&quot;, :value =&gt; &quot;0&quot;)
   end
 
   it &quot;should provide an additional label tag if the :label option is passed in&quot; do
     form = @c.render :label
     form.should match( /&lt;input.*&gt;&lt;label.*&gt;LABEL&lt;\/label&gt;/ )
-    res = form.scan(/&lt;[^&gt;]*&gt;/)
-    res[0].should_not match_tag(:input, :label =&gt; &quot;LABEL&quot;)
+    form.should_not match_tag(:input, :label =&gt; &quot;LABEL&quot;)
   end
 
   it &quot;should not errorify the field for a new object&quot; do
@@ -581,7 +580,7 @@ describe &quot;bound_check_box&quot; do
   it &quot;should be checked if the value of the model's attribute is equal to the value of :on&quot; do
     r = @c.render :checked
     r.should match_tag(:input, :type =&gt;&quot;checkbox&quot;, :value =&gt; &quot;foowee&quot;, :checked =&gt; &quot;checked&quot;)
-    r.should match_tag(:input, :type =&gt;&quot;checkbox&quot;, :value =&gt; &quot;YES&quot;, :checked =&gt; &quot;checked&quot;)
+    r.should match_tag(:input, :type =&gt;&quot;checkbox&quot;, :value =&gt; &quot;YES&quot;)
 
   end
 end
@@ -705,14 +704,11 @@ describe &quot;radio_group&quot; do
   it &quot;should accept array of hashes as options&quot; do
     radio = @c.render :hash
     radio.scan( /&lt;input.*?&gt;&lt;label.*?&gt;(Five|Bar)&lt;\/label&gt;/ ).size.should == 2
-    radio = radio.scan(/&lt;[^&gt;]*&gt;/)
-    radio.size.should == 6
-    radio[0].should match_tag(:input, :value =&gt; 5)
-    radio[1].should match_tag(:label)
-    radio[2].should match_tag('/label')
-    radio[3].should match_tag(:input, :value =&gt; 'bar', :id =&gt; 'bar_id')
-    radio[4].should match_tag(:label, :for =&gt; 'bar_id')
-    radio[5].should match_tag('/label')
+    radio.scan(/&lt;[^&gt;]*&gt;/).size.should == 6
+    radio.should match_tag(:input, :value =&gt; 5)
+    radio.should match_tag(:label)
+    radio.should match_tag(:input, :value =&gt; 'bar', :id =&gt; 'bar_id')
+    radio.should match_tag(:label, :for =&gt; 'bar_id')
   end
 
   it &quot;should apply attributes to each element&quot; do
@@ -740,10 +736,9 @@ describe &quot;bound_radio_group&quot; do
 
   it &quot;should return a group of radio buttons&quot; do
     r = @c.render :basic
-    radio = r.scan(/&lt;[^&gt;]*&gt;/)
-    radio[2].should match_tag(:input, :type =&gt; &quot;radio&quot;, :name =&gt; &quot;fake_model[foo]&quot;, :value =&gt; &quot;foowee&quot;, :checked =&gt; &quot;checked&quot;)
-    radio[5].should match_tag(:input, :type =&gt; &quot;radio&quot;, :name =&gt; &quot;fake_model[foo]&quot;, :value =&gt; &quot;baree&quot;)
-    radio[6].should not_match_tag(:checked =&gt; &quot;checked&quot;)
+    r.should match_tag(:input, :type =&gt; &quot;radio&quot;, :name =&gt; &quot;fake_model[foo]&quot;, :value =&gt; &quot;foowee&quot;, :checked =&gt; &quot;checked&quot;)
+    r.should match_tag(:input, :type =&gt; &quot;radio&quot;, :name =&gt; &quot;fake_model[foo]&quot;, :value =&gt; &quot;baree&quot;)
+    r.should_not match_tag(:checked =&gt; &quot;checked&quot;)
   end
 
   it &quot;should provide an additional label tag for each option in array-based options&quot; do
@@ -757,37 +752,31 @@ describe &quot;bound_radio_group&quot; do
   it &quot;should accept array of hashes as options&quot; do
     r = @c.render :hashes
     r.scan( /&lt;input.*?&gt;&lt;label.*?&gt;(Five|Bar)&lt;\/label&gt;/ ).size.should == 2
-    radio = r.scan(/&lt;[^&gt;]*&gt;/)[2..-2]
-    radio.size.should == 6
-    radio[0].should match_tag(:input, :value =&gt; 5)
-    radio[1].should match_tag(:label)
-    radio[2].should match_tag('/label')
-    radio[3].should match_tag(:input, :value =&gt; 'bar', :id =&gt; 'bar_id')
-    radio[4].should match_tag(:label, :for =&gt; 'bar_id')
-    radio[5].should match_tag('/label')
+    r.scan(/&lt;[^&gt;]*&gt;/)[2..-2].size.should == 6
+    r.should match_tag(:input, :value =&gt; 5)
+    r.should match_tag(:label)
+    r.should match_tag(:input, :value =&gt; 'bar', :id =&gt; 'bar_id')
+    r.should match_tag(:label, :for =&gt; 'bar_id')
   end
 
   it &quot;should provide autogenerated id for inputs&quot; do
     r = @c.render :mixed
-    radio = r.scan(/&lt;[^&gt;]*&gt;/)[2..-2]
-    radio[0].should match_tag(:input, :id =&gt; 'fake_model_foo_bar')
-    radio[1].should match_tag(:label, :for =&gt; 'fake_model_foo_bar')
-    radio[3].should match_tag(:input, :id =&gt; 'fake_model_foo_bar')
-    radio[4].should match_tag(:label, :for =&gt; 'fake_model_foo_bar')
+    r.should match_tag(:input, :id =&gt; 'fake_model_foo_bar')
+    r.should match_tag(:label, :for =&gt; 'fake_model_foo_bar')
+    r.should match_tag(:input, :id =&gt; 'fake_model_foo_bar')
+    r.should match_tag(:label, :for =&gt; 'fake_model_foo_bar')
   end
 
   it &quot;should override autogenerated id for inputs with hash-given id&quot; do
     r = @c.render :override_id
-    radio = r.scan(/&lt;[^&gt;]*&gt;/)[2..-2]
-    radio[0].should match_tag(:input, :id =&gt; 'bar_id')
-    radio[1].should match_tag(:label, :for =&gt; 'bar_id')
+    r.should match_tag(:input, :id =&gt; 'bar_id')
+    r.should match_tag(:label, :for =&gt; 'bar_id')
   end
 
   it &quot;should only have one element with the checked property&quot; do
     r = @c.render :basic
-    radio = r.scan(/&lt;[^&gt;]*&gt;/)[2..-2]
-    radio[0].should match_tag(:input, :checked =&gt; &quot;checked&quot;)
-    radio[3].should_not match_tag(:input, :checked =&gt; &quot;false&quot;)
+    r.should match_tag(:input, :checked =&gt; &quot;checked&quot;)
+    r.should_not match_tag(:input, :checked =&gt; &quot;false&quot;)
   end
 end
 
@@ -819,8 +808,7 @@ describe &quot;text_area&quot; do
   it &quot;should render a label when the label is passed in&quot; do
     result = @c.render :label
     result.should match(/&lt;label.*&gt;LABEL&lt;\/label&gt;&lt;textarea/)
-    res = result.scan(/&lt;[^&gt;]*&gt;/)
-    res[1].should_not match_tag(:textarea, :label =&gt; &quot;LABEL&quot;)
+    result.should_not match_tag(:textarea, :label =&gt; &quot;LABEL&quot;)
   end
   
   it &quot;should be disabled if :disabled =&gt; true is passed in&quot; do
@@ -1035,7 +1023,6 @@ describe &quot;option tags&quot; do
 
   it &quot;should not pollute the &lt;select&gt; attributes with &lt;option&gt; attributes&quot; do
     r = @c.render :clean
-    r = r.slice(/&lt;select[^&gt;]*&gt;/)
     r.should_not match_tag(:select, :value =&gt; &quot;banana&quot;, :selected =&gt; &quot;selected&quot;)
   end
 end
@@ -1048,12 +1035,7 @@ describe &quot;fieldset&quot; do
 
   it &quot;should provide legend option&quot; do
     r = @c.render :legend
-#   res = fieldset :legend =&gt; 'TEST' do
-#     _buffer &lt;&lt; &quot;CONTENT&quot;
-#   end
-    r.should include(&quot;CONTENT&quot;)
-    r.should match_tag(:fieldset, {})
-    r.should match_tag(:legend, :content =&gt; 'TEST')
+    r.should have_selector(&quot;fieldset legend:contains('TEST')&quot;)
   end
 
 end
@@ -1066,8 +1048,7 @@ describe &quot;label&quot; do
 
   it &quot;should render a label tag&quot; do
     r = @c.render :basic
-    #r = label(&quot;First Name&quot;, :id =&gt; &quot;user_first_name&quot;)
-    r.should match_tag(:label, :for =&gt; &quot;user_first_name&quot;, :content =&gt; &quot;First Name&quot;)
+    r.should have_selector(&quot;label[for=user_first_name]:contains('First Name')&quot;)
   end
 end
 
@@ -1079,23 +1060,22 @@ describe &quot;file_field&quot; do
 
   it &quot;should return a basic file field based on the values passed in&quot; do
     r = @c.render :with_values
-    #file_field(:name =&gt; &quot;foo&quot;, :value =&gt; &quot;bar&quot;)
-    r.should match_tag( :input, :type =&gt; &quot;file&quot;, :name =&gt; &quot;foo&quot;, :value =&gt; &quot;bar&quot;)
+    r.should have_selector(&quot;input[type=file][name=foo][value=bar]&quot;)
   end
 
   it &quot;should wrap the field in a label if the :label option is passed to the file&quot; do
     r = @c.render :with_label
-    r.should match(/&lt;label&gt;LABEL&lt;\/label&gt;&lt;input type=&quot;file&quot; class=&quot;file&quot;\s*\/&gt;/)
+    r.should have_selector(&quot;label:contains('LABEL') + input.file[type=file]&quot;)
   end
   
   it &quot;should be disabled if :disabled =&gt; true is passed in&quot; do
     r = @c.render :disabled
-    r.should match_tag(:input, :type =&gt; &quot;file&quot;, :disabled =&gt; &quot;disabled&quot;)
+    r.should have_selector(&quot;input[type=file][disabled=disabled]&quot;)
   end
   
   it &quot;should make the surrounding form multipart&quot; do
     r = @c.render :makes_multipart
-    r.should match_tag(:form, :enctype =&gt; &quot;multipart/form-data&quot;)
+    r.should have_selector(&quot;form[enctype='multipart/form-data']&quot;)
   end
 end
 
@@ -1108,22 +1088,18 @@ describe &quot;bound_file_field&quot; do
 
   it &quot;should take a string object and return a useful file control&quot; do
     r  = @c.render :takes_string
-    r.should match_tag(:input, :type =&gt; &quot;file&quot;, :name =&gt; &quot;fake_model[foo]&quot;, :value =&gt; &quot;foowee&quot;)
+    r.should have_selector(&quot;input[type=file][name='fake_model[foo]'][value=foowee]&quot;)
   end
 
   it &quot;should take additional attributes and use them&quot; do
     r = @c.render :additional_attributes
-    r.should match_tag(:input, :type =&gt; &quot;file&quot;, :name =&gt; &quot;fake_model[foo]&quot;, :value =&gt; &quot;foowee&quot;, :bar =&gt; &quot;7&quot;)
+    r.should have_selector(&quot;input[type=file][name='fake_model[foo]'][value=foowee][bar='7']&quot;)
   end
 
   it &quot;should wrap the file_field in a label if the :label option is passed in&quot; do
     r = @c.render :with_label
-#   form = form_for @obj do
-#     _buffer &lt;&lt; text_field(:foo, :label =&gt; &quot;LABEL&quot;)
-#   end
-    r.should match(/&lt;label.*&gt;LABEL&lt;\/label&gt;&lt;input/)
-    res = r.scan(/&lt;[^&gt;]*&gt;/)
-    res[2].should_not match_tag(:input, :label =&gt; &quot;LABEL&quot;)
+    r.should have_selector(&quot;label:contains('LABEL')&quot;)
+    r.should_not have_selector(&quot;input[label=LABEL]&quot;)
   end
 end
 
@@ -1135,20 +1111,18 @@ describe &quot;submit&quot; do
   
   it &quot;should return a basic submit input based on the values passed in&quot; do
     r = @c.render :submit_with_values
-    r.should match_tag(:input, :type =&gt; &quot;submit&quot;, :name =&gt; &quot;foo&quot;, :value =&gt; &quot;Done&quot;)
+    r.should have_selector(&quot;input[type=submit][name=foo][value=Done]&quot;)
   end
 
   it &quot;should provide an additional label tag if the :label option is passed in&quot; do
     r = @c.render :submit_with_label
-    r.should match(/&lt;input.*type=&quot;submit&quot;/)
-    r.should match(/&lt;input.*name=&quot;submit&quot;/)
-    r.should match(/&lt;input.*value=&quot;Done&quot;/)
-    r.should match(/&lt;label.*&gt;LABEL&lt;\/label&gt;/)
+    r.should have_selector(&quot;input[type=submit][name=submit][value=Done]&quot;)
+    r.should have_selector(&quot;label:contains('LABEL')&quot;)
   end
   
   it &quot;should be disabled if :disabled =&gt; true is passed in&quot; do
     r = @c.render :disabled_submit
-    r.should match_tag(:input, :type =&gt; &quot;submit&quot;, :value =&gt; &quot;Done&quot;, :disabled =&gt; &quot;disabled&quot;)
+    r.should have_selector(&quot;input[type=submit][value=Done][disabled=disabled]&quot;)
   end  
 end
 
@@ -1160,18 +1134,18 @@ describe &quot;button&quot; do
   
   it &quot;should return a button based on the values passed in&quot; do
     r = @c.render :button_with_values
-    r.should match_tag(:button, :type =&gt; &quot;button&quot;, :name =&gt; &quot;foo&quot;, :value =&gt; &quot;bar&quot;, :content =&gt; &quot;Click Me&quot;)
+    r.should have_selector(&quot;button[type=button][name=foo][value=bar]:contains('Click Me')&quot;)
   end
 
   it &quot;should provide an additional label tag if the :label option is passed in&quot; do
     r = @c.render :button_with_label
-    r.should match(/&lt;button.*value=&quot;foo&quot;/)
-    r.should match(/&lt;label.*&gt;LABEL&lt;\/label&gt;/)
+    r.should have_selector(&quot;button[value=foo]&quot;)
+    r.should have_selector(&quot;label:contains('LABEL')&quot;)
   end
 
   it &quot;should be disabled if :disabled =&gt; true is passed in&quot; do
     r = @c.render :disabled_button
-    r.should match_tag(:button, :disabled =&gt; &quot;true&quot;)
+    r.should have_selector(&quot;button[disabled=true]&quot;)
   end
 end
 
@@ -1209,9 +1183,9 @@ describe &quot;custom builder&quot; do
   
   it &quot;should let you override update_unbound_controls&quot; do
     r = @c.render :everything
-    r.should match_tag(:button, :unbound =&gt; &quot;button&quot;)
-    r.should match_tag(:input, :unbound =&gt; &quot;submit&quot;)
-    r.should match_tag(:textarea, :unbound =&gt; &quot;text_area&quot;)
+    r.should have_selector(&quot;button[unbound=button]&quot;)
+    r.should have_selector(&quot;input[unbound=submit]&quot;)
+    r.should have_selector(&quot;textarea[unbound=text_area]&quot;)
   end
 end
 
@@ -1225,28 +1199,28 @@ describe 'delete_button' do
   
   it &quot;should have a default submit button text&quot; do
     result = @controller.render :simple_delete # &lt;%= delete_button @obj %&gt;
-    result.should match(/&lt;input type=\&quot;submit\&quot; value=&quot;Delete&quot;&gt;&lt;\/input&gt;/)
+    result.should have_selector(&quot;input[type=submit][value=Delete]&quot;)
   end
 
   it 'should return a button inside of a form for the object' do
     result = @controller.render :simple_delete # &lt;%= delete_button @obj %&gt;
-    result.should match_tag(:form, :action =&gt; &quot;/fake_models/fake_model&quot;, :method =&gt; &quot;post&quot;)
-    result.should match_tag(:input, :type =&gt; &quot;hidden&quot;, :value =&gt; &quot;DELETE&quot;, :name =&gt; &quot;_method&quot;)
+    result.should have_selector(&quot;form[action='/fake_models/fake_model'][method=post]&quot;)
+    result.should have_selector(&quot;input[type=hidden][value=DELETE][name=_method]&quot;)
   end
 
   it 'should allow you to modify the label' do
     result = @controller.render :delete_with_label # &lt;%= delete_button(@obj, &quot;Delete moi!&quot;) %&gt;
-    result.should match(/&lt;input type=\&quot;submit\&quot; value=\&quot;Delete moi!\&quot;&gt;&lt;\/input&gt;/)
+    result.should have_selector(&quot;input[type=submit][value='Delete moi!']&quot;)
   end
   
   it &quot;should allow you to pass some extra params like a class&quot; do
     result = @controller.render :delete_with_extra_params
-    result.should match(/&lt;input type=\&quot;submit\&quot; class=\&quot;custom-class\&quot; value=\&quot;Delete\&quot;&gt;&lt;\/input&gt;/)
+    result.should have_selector(&quot;input.custom-class[type=submit][value=Delete]&quot;)
   end
   
   it &quot;should allow to pass an explicit url as a string&quot; do
     result = @controller.render :delete_with_explicit_url # &lt;%= delete_button('/test/custom_url') %&gt;
-    result.should match_tag(:form, :action =&gt; &quot;/test/custom_url&quot;, :method =&gt; &quot;post&quot;)
+    result.should have_selector(&quot;form[action='/test/custom_url'][method=post]&quot;)
   end
   
 end</diff>
      <filename>merb-helpers/spec/merb_helpers_form_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -9,38 +9,32 @@ describe Merb::Helpers::Tag do
   
   describe &quot;#tag&quot; do
     it 'generates &lt;div&gt;content&lt;/div&gt; from tag :div, &quot;content&quot;' do
-      response = get &quot;/tag_helper/tag_with_content&quot;
+      response = request &quot;/tag_helper/tag_with_content&quot;
 
-      response.body.should match_tag(:div)
-      response.body.should include(&quot;Astral Projection ~ Dancing Galaxy&quot;)
+      response.should have_selector(&quot;div&quot;)
+      response.body.to_s.should include(&quot;Astral Projection ~ Dancing Galaxy&quot;)
     end
 
     it 'outputs content returned by the block when block is given'  do
-      response = get &quot;/tag_helper/tag_with_content_in_the_block&quot;
+      response = request &quot;/tag_helper/tag_with_content_in_the_block&quot;
 
-      response.body.should match_tag(:div)
+      response.should have_selector(&quot;div&quot;)
       response.body.should include(&quot;Astral Projection ~ Trust in Trance 1&quot;)
     end
 
     it 'generates tag attributes for all of keys of last Hash' do
-      response = get &quot;/tag_helper/tag_with_attributes&quot;
+      response = request &quot;/tag_helper/tag_with_attributes&quot;
 
-      doc = Hpricot(response.body)
-      (doc/&quot;div.psy&quot;).size.should == 1
-      (doc/&quot;div#bands&quot;).size.should == 1
-      (doc/&quot;div[@invalid_attr='at least in html']&quot;).size.should == 1
+      response.should have_selector(&quot;div.psy&quot;)
+      response.should have_selector(&quot;div#bands&quot;)
+      response.should have_selector(&quot;div[invalid_attr='at least in html']&quot;)
     end    
 
     it 'handles nesting of tags/blocks' do
-      response = get &quot;/tag_helper/nested_tags&quot;
+      response = request &quot;/tag_helper/nested_tags&quot;
 
-      doc = Hpricot(response.body)
-      (doc/&quot;div.discography&quot;).size.should == 1
-      (doc/&quot;div.discography&quot;/&quot;ul.albums&quot;).size.should == 1
-      (doc/&quot;div.discography&quot;/&quot;ul.albums&quot;/&quot;li.first&quot;).size.should == 1
-
-      (doc/&quot;#tit&quot;).size.should == 1
-      (doc/&quot;#tit&quot;).first.inner_html.should == &quot;Trust in Trance 2&quot;
+      response.should have_selector(&quot;div.discography ul.albums li.first&quot;)
+      response.should have_selector(&quot;#tit:contains('Trust in Trance 2')&quot;)
     end
   end
 end</diff>
      <filename>merb-helpers/spec/merb_helpers_tag_helper_spec.rb</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>merb-core/lib/merb-core/test/helpers/view_helper.rb</filename>
    </removed>
    <removed>
      <filename>merb-core/spec/public/test/view_helper_spec.rb</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>aa16b61d61499606b54c19b529c18089122bd305</id>
    </parent>
  </parents>
  <author>
    <name>Carl Lerche</name>
    <email>carllerche@mac.com</email>
  </author>
  <url>http://github.com/wycats/merb/commit/de93f6d6c8c1ad45fdd7ab330ab5b4d0bf3bf3b1</url>
  <id>de93f6d6c8c1ad45fdd7ab330ab5b4d0bf3bf3b1</id>
  <committed-date>2008-11-03T13:56:05-08:00</committed-date>
  <authored-date>2008-11-02T19:58:06-08:00</authored-date>
  <message>Convert view matchers to nokogiri with a rexml fallback

The view matchers have_xpath, have_selector, have_tag, matches_tag now
use nokogiri. If nokogiri is not present (for example, in situations
where it cannot be compiled), the matchers fallback on rexml.</message>
  <tree>0627f1d405f132ed2bc178bc69125e908222f64a</tree>
  <committer>
    <name>Carl Lerche</name>
    <email>carllerche@mac.com</email>
  </committer>
</commit>
