rpath 1.0.1 → 1.1.0

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.
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: