Skip to content

Commit

Permalink
* lib/hpricot/elements.rb: added block syntax to attr, new methods…
Browse files Browse the repository at this point in the history
… `remove_attr` and `remove_class`. Got rid of `set`, making it an alias for `attr` which does much more.

git-svn-id: https://code.whytheluckystiff.net/svn/hpricot/trunk@150 9e82565c-fa0a-db11-9fa0-00132028b6dc
  • Loading branch information
why committed Jun 5, 2007
1 parent 594a0be commit 98411be
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 18 deletions.
5 changes: 4 additions & 1 deletion README
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ So, let's go beyond just trying to fix the hierarchy. The


What measures does <tt>:xhtml_strict</tt> take? What measures does <tt>:xhtml_strict</tt> take?


1. Shift elements into their proper containers just like <tt>:fixup_tags</tt>. 1. Shift elements into their proper containers just like :fixup_tags.
2. Remove unknown elements. 2. Remove unknown elements.
3. Remove unknown attributes. 3. Remove unknown attributes.
4. Remove illegal content. 4. Remove illegal content.
Expand All @@ -270,6 +270,9 @@ on the standard mode. The main difference is that :xml mode won't try to output
tags which are friendlier for browsers. For example, if an opening and closing tags which are friendlier for browsers. For example, if an opening and closing
<tt>br</tt> tag is found, XML mode won't try to turn that into an empty element. <tt>br</tt> tag is found, XML mode won't try to turn that into an empty element.


XML mode also doesn't downcase the tags and attributes for you. So pay attention
to case, friends.

The primary way to use Hpricot's XML mode is to call the Hpricot.XML method: The primary way to use Hpricot's XML mode is to call the Hpricot.XML method:


doc = open("http://redhanded.hobix.com/index.xml") do |f| doc = open("http://redhanded.hobix.com/index.xml") do |f|
Expand Down
77 changes: 60 additions & 17 deletions lib/hpricot/elements.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -172,10 +172,36 @@ def wrap(str = nil, &blk)
end end
end end


def attr key, value = nil # Gets and sets attributes on all matched elements.
if value #
# Pass in a +key+ on its own and this method will return the string value
# assigned to that attribute for the first elements. Or +nil+ if the
# attribute isn't found.
#
# doc.search("a").attr("href")
# #=> "http://hacketyhack.net/"
#
# Or, pass in a +key+ and +value+. This will set an attribute for all
# matched elements.
#
# doc.search("p").attr("class", "basic")
#
# You may also use a Hash to set a series of attributes:
#
# (doc/"a").attr(:class => "basic", :href => "http://hackety.org/")
#
# Lastly, a block can be used to rewrite an attribute based on the element
# it belongs to. The block will pass in an element. Return from the block
# the new value of the attribute.
#
# records.attr("href") { |e| e['href'] + "#top" }
#
# This example adds a <tt>#top</tt> anchor to each link.
#
def attr key, value = nil, &blk
if value or blk
each do |el| each do |el|
el.set_attribute(key, value) el.set_attribute(key, value || blk[el])
end end
return self return self
end end
Expand All @@ -186,7 +212,13 @@ def attr key, value = nil
return self[0].get_attribute(key) return self[0].get_attribute(key)
end end
end end
alias_method :set, :attr


# Adds the class to all matched elements.
#
# (doc/"p").add_class("bacon")
#
# Now all paragraphs will have class="bacon".
def add_class class_name def add_class class_name
each do |el| each do |el|
next unless el.respond_to? :get_attribute next unless el.respond_to? :get_attribute
Expand All @@ -196,26 +228,37 @@ def add_class class_name
self self
end end


# Sets an attribute for all elements in this list. You may use # Remove an attribute from each of the matched elements.
# a simple pair (<em>attribute name</em>, <em>attribute value</em>):
# #
# doc.search('p').set(:class, 'outline') # (doc/"input").remove_attr("disabled")
# #
# Or, use a hash of pairs: def remove_attr name
each do |el|
next unless el.respond_to? :remove_attribute
el.remove_attribute(name)
end
self
end

# Removes a class from all matched elements.
# #
# doc.search('div#sidebar').set(:class => 'outline', :id => 'topbar') # (doc/"span").remove_class("lightgrey")
# #
def set(k, v = nil) # Or, to remove all classes:
case k #
when Hash # (doc/"span").remove_class
each do |node| #
k.each { |a,b| node.set_attribute(a, b) } def remove_class name = nil
end each do |el|
else next unless el.respond_to? :get_attribute
each do |node| if name
node.set_attribute(k, v) classes = el.get_attribute('class').to_s.split(" ")
el.set_attribute('class', (classes - [name]).uniq.join(" "))
else
el.remove_attribute("class")
end end
end end
self
end end


ATTR_RE = %r!\[ *(?:(@)([\w\(\)-]+)|([\w\(\)-]+\(\))) *([~\!\|\*$\^=]*) *'?"?([^\]'"]*)'?"? *\]!i ATTR_RE = %r!\[ *(?:(@)([\w\(\)-]+)|([\w\(\)-]+\(\))) *([~\!\|\*$\^=]*) *'?"?([^\]'"]*)'?"? *\]!i
Expand Down
17 changes: 17 additions & 0 deletions test/test_alter.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -37,10 +37,27 @@ def test_add_class
def test_change_attributes def test_change_attributes
all_ps = (@basic/"p").attr("title", "Some Title") all_ps = (@basic/"p").attr("title", "Some Title")
all_as = (@basic/"a").attr("href", "http://my_new_href.com") all_as = (@basic/"a").attr("href", "http://my_new_href.com")
all_lb = (@basic/"link").attr("href") { |e| e.name }
assert_changed(@basic, "p", all_ps) {|p| p.attributes["title"] == "Some Title"} assert_changed(@basic, "p", all_ps) {|p| p.attributes["title"] == "Some Title"}
assert_changed(@basic, "a", all_as) {|a| a.attributes["href"] == "http://my_new_href.com"} assert_changed(@basic, "a", all_as) {|a| a.attributes["href"] == "http://my_new_href.com"}
assert_changed(@basic, "link", all_lb) {|a| a.attributes["href"] == "link" }
end end


def test_remove_attr
all_rl = (@basic/"link").remove_attr("href")
assert_changed(@basic, "link", all_rl) { |link| link['href'].nil? }
end

def test_remove_class
all_c1 = (@basic/"p[@class*='last']").remove_class("last")
assert_changed(@basic, "p[@class*='last']", all_c1) { |p| p['class'] == 'final' }
end

def test_remove_all_classes
all_c2 = (@basic/"p[@class]").remove_class
assert_changed(@basic, "p[@class]", all_c2) { |p| p['class'].nil? }
end

def assert_changed original, selector, set, &block def assert_changed original, selector, set, &block
assert set.all?(&block) assert set.all?(&block)
assert Hpricot(original.to_html).search(selector).all?(&block) assert Hpricot(original.to_html).search(selector).all?(&block)
Expand Down

0 comments on commit 98411be

Please sign in to comment.