rpath 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MTRkMWY4ZDJmNzk1MGM0ZTg3MGNmZWNkMjM4YjUxNjAyM2FiYWIxYQ==
5
- data.tar.gz: !binary |-
6
- NDgxYmM5N2EzNjk0N2I3ZDFhM2M2MmU0ZTlmN2M2MjQ2NTA3MjBkOQ==
2
+ SHA1:
3
+ metadata.gz: ca43180768c5384613ebf5bee029b8e05b7d0875
4
+ data.tar.gz: 7e86e33589477ab8d9a62e1ccf5dde9154fcf3fc
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- MmM5ZjE5MjE3MmVhMDkxYTIwODkxY2FhZWVhMjJkZGQwNjQ0NDk0MTBhYjU0
10
- YzgyOWI0ZTFmYWFlNzlkNDNlNGE4ODRkMGI4MjRlN2RiNmEyYThlNTk0YzM3
11
- MzVjNDYwM2RiZDNjYThiNmIwMjUwNTRjMmQ3ZGJjODI0ZGY4YmM=
12
- data.tar.gz: !binary |-
13
- MDIxOTQwM2RhMDYwODY1OWUzY2QyY2NjYzBjNjU1Y2M1Yzg3NzFiNzAyMzQw
14
- NTFjMzNiZTg4Y2E5NDFmODQyZGVmY2Y5MTllNWY3YTdlYzgxODgzMTE3ZDEx
15
- YjBjNDk3YzYwMmVhY2IwZWZhZTdlNDViODgwZTRkOWQ2ZDM4OTA=
6
+ metadata.gz: d703e513a8e18b418148812010799d76b140ddebf74f67505772d5ab8a4bfdce69ed65f90c83191d74a0a7831efca6781a40002439e6e8010e0aa3b91bcddc35
7
+ data.tar.gz: a3ebe23c2b83ca6f24a53ee78e7e04315e7ea5295a730723c678190e5a16b0e10f639ff254b88f9ef536e25caf296d382f573f3092e5b36dbdaaeb601ccdec36
@@ -0,0 +1,4 @@
1
+ --no-private
2
+ -
3
+ README.md
4
+ LICENSE.txt
data/README.md CHANGED
@@ -1,14 +1,15 @@
1
1
  # RPath
2
2
 
3
- "Don't do this." —[flavorjones](https://github.com/flavorjones) [[1]](http://www.nokogiri.org/tutorials/searching_a_xml_html_document.html)
3
+ "Don't use this." —[flavorjones](https://github.com/flavorjones) [[1]](http://www.nokogiri.org/tutorials/searching_a_xml_html_document.html)
4
4
 
5
5
  [![Gem Version](https://badge.fury.io/rb/rpath.svg)](http://badge.fury.io/rb/rpath)
6
+ [![Build Status](https://travis-ci.org/jonahb/rpath.svg?branch=master)](https://travis-ci.org/jonahb/rpath)
6
7
 
7
8
  ## Overview
8
9
 
9
- RPath lets you traverse graphs, such as XML documents, with just Ruby.
10
+ RPath lets you query graphs, such as XML documents, with just Ruby.
10
11
 
11
- RPath can operate on [Nokogiri](http://www.nokogiri.org) documents, [REXML](http://www.germane-software.com/software/rexml/) documents, and the filesystem. Building adapters for other graphs is simple.
12
+ RPath can operate on [Nokogiri](http://www.nokogiri.org) documents, [REXML](http://www.germane-software.com/software/rexml/) documents, [Oga](https://github.com/YorickPeterse/oga) documents, and the filesystem. Building adapters for other graphs is simple.
12
13
 
13
14
  Leading members of the Ruby community have [warned against](http://www.nokogiri.org/tutorials/searching_a_xml_html_document.html) RPath's approach. They're probably right! RPath is as much an experiment as a useful tool.
14
15
 
@@ -52,13 +53,13 @@ exp = RPath { places.place[:name] }
52
53
  exp.eval(xml) # => "Green-Wood"
53
54
  ```
54
55
 
55
- Or, if we only plan to use the expression once, we can combine the two lines above, passing the graph to `RPath`. RPath evaluates the expression and returns the result:
56
+ If we only plan to use the expression once, we can pass the graph to `RPath`. RPath evaluates the expression and returns the result:
56
57
 
57
58
  ```ruby
58
59
  RPath(xml) { places.place[:name] } # => "Green-Wood"
59
60
  ```
60
61
 
61
- For even more succinct syntax, RPath adds to Nokogiri the `#rpath` method:
62
+ Some adapters, such as the built-in Nokogiri adapter, may add convenience methods that make the syntax even prettier:
62
63
 
63
64
  ```ruby
64
65
  xml.rpath { places.place[:name] } # => "Green-Wood"
@@ -74,11 +75,11 @@ In an RPath [graph](http://en.wikipedia.org/wiki/Graph_(mathematics)),
74
75
  * Each vertex has zero or more named attributes, and
75
76
  * Each vertex may have associated data called "content."
76
77
 
77
- RPath expressions assume only this abstract model. They can be applied to any graph for which there is an adapter.
78
+ Adapters implement this abstraction for a particular type of graph. RPath can operate on any graph for which there is an adapter.
78
79
 
79
80
  ## Expressions
80
81
 
81
- An RPath expression, given a graph, produces a value—a vertex, a vertex array, the value of an attribute, or a vertex's content. RPath expressions are constructed by chaining methods inside the block passed to `RPath`.
82
+ An RPath expression, given a graph, selects a value—a vertex, a vertex array, the value of an attribute, or a vertex's content. RPath expressions are constructed by chaining methods inside the block passed to `RPath`.
82
83
 
83
84
  ### Selecting Vertices
84
85
 
@@ -202,6 +203,16 @@ xml = REXML::Document.new('<foo bar="baz"/>')
202
203
  xml.rpath { foo['bar'] } # => "baz"
203
204
  ```
204
205
 
206
+ ### Oga
207
+
208
+ RPath expressions may be evaluated on an `Oga::XML::Document` or an `Oga::XML::Element`.
209
+
210
+ ```ruby
211
+ RPath.use :oga
212
+ xml = Oga.parse_xml('<foo bar="baz"/>')
213
+ xml.rpath { foo['bar'] } # => "baz"
214
+ ```
215
+
205
216
  ### Filesystem
206
217
 
207
218
  The filesystem adapter exposes files and directories as vertices. Directory entries are adjacent to their directory. Expressions may be evaluated on any directory:
@@ -227,36 +238,44 @@ RPath('/', :filesystem) { etc.hostname.content } # => "jbook"
227
238
 
228
239
  ## Custom Adapters
229
240
 
230
- Custom adapters are subclasses of `RPath::Adapter`. They implement three abstract methods: `#adjacent`, `#attribute`, and `#content`. See the implementations in `RPath::Adapters` for examples.
241
+ Custom adapters allow RPath expressions to operate on new types of graphs. To create a custom adapter, subclass `RPath::Adapter` and implement the abstract methods `#adjacent`, `#attribute`, `#content`, and `#name`. See the implementations in `RPath::Adapters` for examples.
242
+
243
+ Once you've implemented a custom adapter, pass an instance to `#RPath`:
244
+
245
+ ```ruby
246
+ RPath(graph, CustomAdapter.new) { foo.bar }
247
+ ```
231
248
 
232
- Register a custom adapter by passing an instance to `RPath.use`:
249
+ To avoid creating an instance for every evaluation, register the adapter and pass the underscored, symbolized class to `RPath`:
233
250
 
234
251
  ```ruby
235
- RPath.use MapsAdapter.new
252
+ RPath.use CustomAdapter.new
253
+ RPath(graph, :custom_adapter) { foo.bar }
236
254
  ```
237
255
 
238
- To use the adapter, pass the underscored, symbolized class name as the second argument to `RPath` or `RPath::Expression#eval`:
256
+ If that's too long, pass a custom ID to `RPath.use`:
239
257
 
240
258
  ```ruby
241
- RPath(map, :maps_adapter) { ... }
259
+ RPath.use CustomAdapter.new, :custom
260
+ RPath(graph, :custom) { foo.bar }
242
261
  ```
243
262
 
244
- You can eliminate the need to specify the adapter by implementing `RPath::Adapter#adapts?`:
263
+ Or, to avoid specifying the adapter altogether—as the built-in XML adapters do—implement `#adapts?` in your adapter class:
245
264
 
246
265
  ```ruby
247
- class MapsAdapter < RPath::Adapter
266
+ class CustomAdapter < RPath::Adapter
248
267
  def adapts?(graph)
249
- graph.is_a? Map
268
+ graph.is_a? CustomGraph
250
269
  end
251
- ...
270
+ # ...
252
271
  end
253
272
  ```
254
273
 
255
- Now RPath will select `MapsAdapter` when an expression is evaluated on a `Map`:
274
+ Now RPath will select a registered `CustomAdapter` when an expression is evaluated on a `CustomGraph`:
256
275
 
257
276
  ```ruby
258
- RPath.use MapsAdapter.new
259
- RPath(Map.new) { ... }
277
+ RPath.use CustomAdapter.new
278
+ RPath(CustomGraph.new) { foo.bar }
260
279
  ```
261
280
 
262
281
  ## Contributing
@@ -2,6 +2,7 @@ module RPath
2
2
  module Adapters
3
3
  autoload :Filesystem, 'rpath/adapters/filesystem'
4
4
  autoload :Nokogiri, 'rpath/adapters/nokogiri'
5
+ autoload :Oga, 'rpath/adapters/oga'
5
6
  autoload :REXML, 'rpath/adapters/rexml'
6
7
  end
7
8
  end
@@ -0,0 +1,79 @@
1
+ require 'oga'
2
+
3
+ module RPath
4
+ module Adapters
5
+
6
+ class Oga < RPath::Adapter
7
+
8
+ # Returns +true+ iff +graph+ is an Oga::XML::Document or an Oga::XML::Element
9
+ # @param [Object] graph
10
+ # @return [Boolean]
11
+ def adapts?(graph)
12
+ graph.is_a?(::Oga::XML::Element) || graph.is_a?(::Oga::XML::Document)
13
+ end
14
+
15
+ # Returns the name of the given node
16
+ # @param [Oga::XML::Document, Oga::XML::Element] vertex
17
+ # @return [String]
18
+ def name(vertex)
19
+ vertex.is_a?(::Oga::XML::Element) ? vertex.name : nil
20
+ end
21
+
22
+ # Returns the child elements of the given node
23
+ # @param [Oga::XML::Document, Oga::XML::Element] vertex
24
+ # @return [Array<Oga::XML::Element>]
25
+ def adjacent(vertex)
26
+ vertex.children.select { |child| child.is_a?(::Oga::XML::Element) }
27
+ end
28
+
29
+ # Returns the value of the named attribute on the given node.
30
+ # @param [Oga::XML::Document, Oga::XML::Element] vertex
31
+ # @param [String, Symbol] name
32
+ # @return [String, nil]
33
+ def attribute(vertex, name)
34
+ if vertex.is_a?(::Oga::XML::Element)
35
+ attr = vertex.attr(name)
36
+ attr && attr.value
37
+ else
38
+ nil
39
+ end
40
+ end
41
+
42
+ # Returns the text content of the given node.
43
+ # @param [Oga::XML::Document, Oga::XML::Element] vertex
44
+ # @return [String, nil]
45
+ def content(vertex)
46
+ vertex.is_a?(::Oga::XML::Element) ? vertex.text : nil
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+
53
+ class Oga::XML::Document
54
+ # Evaluates an RPath expression on the document
55
+ # @example
56
+ # RPath.use :oga
57
+ # xml = Oga.parse_xml('<foo bar="baz"/>')
58
+ # xml.rpath { foo['bar'] } # => "baz"
59
+ # @see #RPath
60
+ # @return [Object]
61
+ #
62
+ def rpath(&block)
63
+ RPath self, :oga, &block
64
+ end
65
+ end
66
+
67
+ class Oga::XML::Element
68
+ # Evaluates an RPath expression on the element
69
+ # @example
70
+ # RPath.use :oga
71
+ # xml = Oga.parse_xml('<foo><bar baz="qux"/></foo>')
72
+ # xml.children.first.rpath { bar['baz'] } # => "qux"
73
+ # @see #RPath
74
+ # @return [Object]
75
+ #
76
+ def rpath(&block)
77
+ RPath self, :oga, &block
78
+ end
79
+ end
@@ -14,7 +14,7 @@ module RPath
14
14
  # @return [Object]
15
15
  # @raise [RuntimeError]
16
16
  # The adapter can't be determined
17
- # @ raise [ArgumentError]
17
+ # @raise [ArgumentError]
18
18
  # +adapter+ is not an {Adapter}, Symbol, or nil
19
19
  # @see #RPath
20
20
  # @see RPath.use
@@ -24,7 +24,7 @@ module RPath
24
24
  when RPath::Adapter
25
25
  adapter
26
26
  when Symbol
27
- Registry.find adapter.to_sym
27
+ Registry.find adapter
28
28
  when nil
29
29
  Registry.infer graph
30
30
  else
@@ -1,3 +1,3 @@
1
1
  module RPath
2
- VERSION = '1.0.1'
2
+ VERSION = '1.1.0'
3
3
  end
metadata CHANGED
@@ -1,69 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rpath
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonah Burke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-03 00:00:00.000000000 Z
11
+ date: 2015-02-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: 1.6.0
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.6.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.7'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: oga
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.2.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.2.0
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
- - - ~>
59
+ - - "~>"
46
60
  - !ruby/object:Gem::Version
47
61
  version: '10.0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - ~>
66
+ - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '10.0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: yard
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
- - - ~>
73
+ - - "~>"
60
74
  - !ruby/object:Gem::Version
61
75
  version: 0.8.7
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
- - - ~>
80
+ - - "~>"
67
81
  - !ruby/object:Gem::Version
68
82
  version: 0.8.7
69
83
  description:
@@ -73,6 +87,7 @@ executables: []
73
87
  extensions: []
74
88
  extra_rdoc_files: []
75
89
  files:
90
+ - ".yardopts"
76
91
  - LICENSE.txt
77
92
  - README.md
78
93
  - lib/rpath.rb
@@ -80,6 +95,7 @@ files:
80
95
  - lib/rpath/adapters.rb
81
96
  - lib/rpath/adapters/filesystem.rb
82
97
  - lib/rpath/adapters/nokogiri.rb
98
+ - lib/rpath/adapters/oga.rb
83
99
  - lib/rpath/adapters/rexml.rb
84
100
  - lib/rpath/expressions.rb
85
101
  - lib/rpath/registry.rb
@@ -95,12 +111,12 @@ require_paths:
95
111
  - lib
96
112
  required_ruby_version: !ruby/object:Gem::Requirement
97
113
  requirements:
98
- - - ! '>='
114
+ - - ">="
99
115
  - !ruby/object:Gem::Version
100
116
  version: 1.9.3
101
117
  required_rubygems_version: !ruby/object:Gem::Requirement
102
118
  requirements:
103
- - - ! '>='
119
+ - - ">="
104
120
  - !ruby/object:Gem::Version
105
121
  version: '0'
106
122
  requirements: []
@@ -108,6 +124,6 @@ rubyforge_project:
108
124
  rubygems_version: 2.4.5
109
125
  signing_key:
110
126
  specification_version: 4
111
- summary: Graph traversal with just Ruby
127
+ summary: Query XML with just Ruby
112
128
  test_files: []
113
129
  has_rdoc: