rasantiago-tiny_xpath_helper 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.rdoc CHANGED
@@ -26,17 +26,53 @@ If you just want the first match, use #first
26
26
  => "one"
27
27
 
28
28
  A slightly more elaborate API is available as #find_xpath
29
- >> xpath.find_xpath( 'node/@style', :format => :xml, :find => :first )
29
+ >> xpath.find_xpath( 'node/@style', :format => :rexml, :find => :first )
30
30
  => style='first'
31
31
 
32
- Where :format can be :text (returns a string), or :xml (returns a REXML element),
32
+ Where :format can be :text (returns a string), or :rexml (returns a REXML element),
33
33
  and :find can be :first or :all
34
+ >> xpath.find_xpath( 'node/@style', :format => :rexml, :find => :all )
35
+ => [style='first']
34
36
 
35
- >> xpath.find_xpath( 'node/@style', :format => :xml, :find => :all )
37
+ If you only need to set :format, you may pass just the symbol instead of an options hash
38
+ This is especially convenient using the [] syntax since a bug in ruby1.8
39
+ prevents using => inside of []
40
+ >> xpath[ 'node/@style', :rexml ]
36
41
  => [style='first']
37
42
 
38
- The output from :format => :xml is suitable for passing to another TinyXPathHelper
39
- >> node_tree = xpath.find_xpath( 'node/three', :format => :xml )
43
+ If you want to filter the output, you can pass something that can be to_proc'd as :format
44
+ (Note that this acts on the string value of the element, not the REXML node)
45
+ >> xpath[ 'node/@style', :to_i ]
46
+ => [0]
47
+
48
+ >> xpath[ 'node/@style', :length ]
49
+ => [5]
50
+
51
+ >> xpath[ 'node', lambda{|x| x.strip.split(//) } ]
52
+ => [["o", "n", "e"], ["t", "w", "o"], ["t", "h", "r", "e", "e"]]
53
+
54
+
55
+ You can also pass a block, which will get called on the entire return value, but
56
+ only if at least one element is found
57
+ >> xpath.all( 'node' ){ |nodes| nodes.count } # nodes is an array
58
+ => 3
59
+
60
+ >> xpath.first( 'node' ){ |node| node.reverse } # node is a string
61
+ => "eno"
62
+
63
+ >> xpath.all( 'node', &:count )
64
+ => 3
65
+
66
+ >> xpath.all( 'nothing' ){ |nodes| raise "this will not run" }
67
+ => []
68
+
69
+ There's no shortcut for the case where you want to run something over the array of matching REXML nodes.
70
+ Just use Array#map for that.
71
+ >> xpath[ 'node', :rexml ].map(&:name)
72
+ => ['node', 'node', 'node']
73
+
74
+ The output from :format => :rexml is suitable for passing to another TinyXPathHelper
75
+ >> node_tree = xpath.find_xpath( 'node/three', :format => :rexml )
40
76
  >> deeper_xpath = TinyXPathHelper.new( node_tree )
41
77
  >> deeper_xpath[ 'b/@beta' ]
42
78
  => ["true"]
@@ -13,22 +13,35 @@ class TinyXPathHelper
13
13
  @options.dup
14
14
  end
15
15
 
16
- def find_xpath(xpath_expr, options = {})
17
- self.class.find_xpath_from( node, xpath_expr, default_options.update(options) )
16
+ def with_options(*options)
17
+ r = default_options
18
+
19
+ options.each do |option|
20
+ if not Hash === option
21
+ option = {:format => option}
22
+ end
23
+ r.update(option)
24
+ end
25
+
26
+ return r
27
+ end
28
+
29
+ def find_xpath(xpath_expr, options = {}, &blk)
30
+ self.class.find_xpath_from( node, xpath_expr, with_options(options), &blk)
18
31
  end
19
32
 
20
- def first(xpath_expr, options = {})
21
- self.find_xpath( xpath_expr, default_options.update(options).update(:find => :first) )
33
+ def first(xpath_expr, options = {}, &blk)
34
+ self.find_xpath( xpath_expr, with_options(options, :find => :first), &blk)
22
35
  end
23
36
  alias at first
24
37
 
25
- def all(xpath_expr, options = {})
26
- self.find_xpath( xpath_expr, default_options.update(options).update(:find => :all) )
38
+ def all(xpath_expr, options = {}, &blk)
39
+ self.find_xpath( xpath_expr, with_options(options, :find => :all), &blk)
27
40
  end
28
41
  alias [] all
29
42
 
30
43
  def self.io_stream_classes
31
- [ IOStream ] rescue [ IO, StringIO ] # thoughtbot-paperclip fixes the ducktype mess here
44
+ [ IOStream ] rescue [ IO, StringIO ] # thoughtbot-paperclip fixes the ducktype mess in StringIO
32
45
  end
33
46
 
34
47
  def self.classes_that_are_xmlish
@@ -77,31 +90,44 @@ class TinyXPathHelper
77
90
 
78
91
  count = options[:find] || :first
79
92
 
80
- if format == :text
81
- filter = lambda{|node| node && xml_node_to_text(node) }
82
- elsif format == :xml
83
- filter = lambda{|node| node }
93
+ filter1 = self.method(:xml_node_to_text)
94
+ filter2 = nil
95
+
96
+ if format == :xml or format == :rexml
97
+ filter1 = nil
98
+ elsif format == :text
99
+ filter2 = nil
100
+ elsif format.respond_to? :to_proc
101
+ filter2 = format.to_proc
84
102
  else
85
103
  raise "I don't know the format #{format.inspect}"
86
104
  end
87
105
 
88
- if count == :all
89
- val = REXML::XPath.match(element, path).map do |node|
90
- filter.call( node )
91
- end
106
+
107
+ if count == :all
108
+ elements = REXML::XPath.match(element, path)
109
+
92
110
  elsif count == :first
93
- val = filter.call(
94
- REXML::XPath.first(element, path)
95
- )
111
+ elements = [ REXML::XPath.first(element, path) ].compact # Haskell hacker wishing for the Maybe monad
112
+
96
113
  else
97
114
  raise "I don't know how to find #{count.inspect}"
98
115
  end
99
116
 
100
- if(blk)
101
- return val if val == nil or val == []
102
- return blk.call(val)
117
+ elements = elements.map(&filter1).map(&filter2)
118
+
119
+ if count == :all
120
+ r = elements
121
+ elsif count == :first
122
+ r = elements.first
103
123
  end
104
- return val
124
+
125
+ if(blk and elements.length > 0)
126
+ return blk.call( r )
127
+ end
128
+
129
+ return r
130
+
105
131
  end
106
132
 
107
133
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{tiny_xpath_helper}
5
- s.version = "0.1.3"
5
+ s.version = "0.1.4"
6
6
 
7
7
  s.authors = ["Jesse Wolfe"]
8
8
  s.date = %q{2009-06-01}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rasantiago-tiny_xpath_helper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jesse Wolfe