om 3.1.0 → 3.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/{COMMON_OM_PATTERNS.textile → COMMON_OM_PATTERNS.md} +136 -126
  3. data/CONTRIBUTING.md +2 -2
  4. data/GETTING_FANCY.md +153 -0
  5. data/GETTING_STARTED.md +329 -0
  6. data/Gemfile +1 -1
  7. data/History.md +164 -0
  8. data/LICENSE +15 -20
  9. data/QUERYING_DOCUMENTS.md +162 -0
  10. data/README.md +2 -2
  11. data/UPDATING_DOCUMENTS.md +6 -0
  12. data/gemfiles/gemfile.rails3 +1 -1
  13. data/gemfiles/gemfile.rails4 +1 -1
  14. data/lib/om/version.rb +1 -1
  15. data/lib/om/xml/dynamic_node.rb +42 -51
  16. data/lib/tasks/om.rake +1 -1
  17. data/om.gemspec +1 -2
  18. data/spec/integration/differentiated_elements_spec.rb +2 -2
  19. data/spec/integration/element_value_spec.rb +13 -13
  20. data/spec/integration/proxies_and_ref_spec.rb +10 -10
  21. data/spec/integration/querying_documents_spec.rb +20 -27
  22. data/spec/integration/rights_metadata_integration_example_spec.rb +4 -4
  23. data/spec/integration/selective_querying_spec.rb +1 -1
  24. data/spec/integration/serialization_spec.rb +15 -15
  25. data/spec/integration/set_reentrant_terminology_spec.rb +6 -6
  26. data/spec/integration/subclass_terminology_spec.rb +8 -8
  27. data/spec/integration/xpathy_stuff_spec.rb +10 -10
  28. data/spec/unit/container_spec.rb +27 -27
  29. data/spec/unit/document_spec.rb +24 -24
  30. data/spec/unit/dynamic_node_spec.rb +60 -49
  31. data/spec/unit/named_term_proxy_spec.rb +12 -7
  32. data/spec/unit/node_generator_spec.rb +4 -4
  33. data/spec/unit/nokogiri_sanity_spec.rb +17 -18
  34. data/spec/unit/om_spec.rb +2 -2
  35. data/spec/unit/template_registry_spec.rb +51 -51
  36. data/spec/unit/term_builder_spec.rb +45 -44
  37. data/spec/unit/term_spec.rb +55 -55
  38. data/spec/unit/term_value_operators_spec.rb +205 -205
  39. data/spec/unit/term_xpath_generator_spec.rb +33 -36
  40. data/spec/unit/terminology_builder_spec.rb +50 -47
  41. data/spec/unit/terminology_spec.rb +92 -92
  42. data/spec/unit/validation_spec.rb +12 -12
  43. data/spec/unit/xml_serialization_spec.rb +20 -20
  44. data/spec/unit/xml_spec.rb +3 -3
  45. data/spec/unit/xml_terminology_based_solrizer_spec.rb +18 -18
  46. metadata +11 -38
  47. data/GETTING_FANCY.textile +0 -145
  48. data/GETTING_STARTED.textile +0 -254
  49. data/History.textile +0 -186
  50. data/QUERYING_DOCUMENTS.textile +0 -139
  51. data/UPDATING_DOCUMENTS.textile +0 -3
data/LICENSE CHANGED
@@ -1,20 +1,15 @@
1
- Copyright (c) 2009 Matt Zumwalt
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ ##########################################################################
2
+ # Copyright (c) 2009 Matt Zumwalt
3
+ # Additional copyright may be held by others, as reflected in the commit log
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
@@ -0,0 +1,162 @@
1
+ # Querying OM Documents
2
+
3
+ This document will help you understand how to access the information
4
+ associated with an [OM::XML::Document](OM/XML/Document.html) object. We
5
+ will explain some of the methods provided by the
6
+ [OM::XML::Document](OM/XML/Document.html) module and its related modules
7
+ [OM::XML::TermXPathGenerator](OM/XML/TermXPathGenerator.html) &
8
+ [OM::XML::TermValueOperators](OM/XML/TermValueOperators.html)
9
+
10
+ *Note: In your code, don’t worry about including
11
+ `OM::XML::TermXPathGenerator` and `OM::XML::TermValueOperators` into your
12
+ classes. `OM::XML::Document` handles that for you.*
13
+
14
+ ### Load the Sample XML and Sample Terminology
15
+
16
+ These examples use the Document class defined in
17
+ [OM::Samples::ModsArticle](https://github.com/projecthydra/om/blob/master/lib/om/samples/mods_article.rb)
18
+
19
+ Download
20
+ [hydrangea\_article1.xml](https://github.com/projecthydra/om/blob/master/spec/fixtures/mods_articles/hydrangea_article1.xml)
21
+ (sample xml) into your working directory, then run this in irb:
22
+
23
+ ```ruby
24
+ require "om/samples"
25
+ sample_xml = File.new("hydrangea_article1.xml")
26
+ doc = OM::Samples::ModsArticle.from_xml(sample_xml)
27
+ ```
28
+
29
+ ## Querying the [OM::XML::Document](OM/XML/Document.html)
30
+
31
+ The [OM::XML::Terminology](OM/XML/Terminology.html") declared by
32
+ [OM::Samples::ModsArticle](https://github.com/projecthydra/om/blob/master/lib/om/samples/mods_article.rb)
33
+ maps the defined Terminology structure to xpath queries. It will also run the queries for you in most cases.
34
+
35
+ #### xpath\_for method of [OM::XML::Terminology](OM/XML/Terminology.html") retrieves xpath expressions for OM terms
36
+
37
+ The `xpath_for` method retrieves the xpath used by the
38
+ [OM::XML::Terminology](OM/XML/Terminology.html")
39
+
40
+ Examples of xpaths for `:name` and two variants of `:name` that were created
41
+ using the `:ref` argument in the Terminology builder:
42
+
43
+ ```ruby
44
+ OM::Samples::ModsArticle.terminology.xpath_for(:name)
45
+ => "//oxns:name"
46
+ OM::Samples::ModsArticle.terminology.xpath_for(:person)
47
+ => "//oxns:name[@type=\"personal\"]"
48
+ OM::Samples::ModsArticle.terminology.xpath_for(:organization)
49
+ => "//oxns:name[@type=\"corporate\"]"
50
+ ```
51
+
52
+ #### Working with Terms
53
+
54
+ To retrieve the values of xml nodes, use the `term_values` method:
55
+
56
+ ```ruby
57
+ doc.term_values(:person, :first_name)
58
+ doc.term_values(:person, :last_name)
59
+ ```
60
+
61
+ The `term_values` method is defined in the
62
+ [OM::XML::TermValueOperators](OM/XML/TermValueOperators.html) module,
63
+ which is included in [OM::XML::Document](OM/XML/Document.html)
64
+
65
+ Not that if a term’s xpath mapping points to XML nodes that contain
66
+ other nodes, the response to term\_values will be `Nokogiri::XML::Node`
67
+ objects instead of text values:
68
+
69
+ doc.term_values(:name)
70
+
71
+ More examples of using term\_values and find\_by\_terms (defined in
72
+ [OM::XML::Document](OM/XML/Document.html)):
73
+
74
+ ```ruby
75
+ doc.find_by_terms(:organization).to_xml
76
+ doc.term_values(:organization, :role)
77
+ => ["\n Funder\n "]
78
+ doc.term_values(:organization, :namePart)
79
+ => ["NSF"]
80
+ ```
81
+
82
+ To retrieve the values of nested terms, create a sequence of terms, from
83
+ outermost to innermost:
84
+
85
+ ```ruby
86
+ OM::Samples::ModsArticle.terminology.xpath_for(:journal, :issue, :pages, :start)
87
+ => "//oxns:relatedItem[@type=\"host\"]/oxns:part/oxns:extent[@unit=\"pages\"]/oxns:start"
88
+ doc.term_values(:journal, :issue, :pages, :start)
89
+ => ["195"]
90
+ ```
91
+
92
+ If you get one of the term names wrong in the sequence, OM will tell you
93
+ which one is causing problems. See what happens when you put :page
94
+ instead of :pages in your argument to term\_values.
95
+
96
+ ```ruby
97
+ doc.term_values(:journal, :issue, :page, :start)
98
+ # OM::XML::Terminology::BadPointerError: You attempted to retrieve a Term using this pointer: [:journal, :issue, :page] but no Term exists at that location. Everything is fine until ":page", which doesn't exist.
99
+ ```
100
+
101
+ ### When XML Elements are Reused in a Document
102
+
103
+ Another way to put this: the xpath statement for a term can be ambiguous.
104
+
105
+ In our MODS document, we have two distinct uses of the title XML element:
106
+
107
+ 1. title of the published article,
108
+ 2. title of the journal it was published in.
109
+
110
+ How can we distinguish between these two uses?
111
+
112
+ ```ruby
113
+ doc.term_values(:title_info, :main_title)
114
+ => ["ARTICLE TITLE", "VARYING FORM OF TITLE", "TITLE OF HOST JOURNAL"]
115
+ doc.term_values(:mods, :title_info, :main_title)
116
+ => ["ARTICLE TITLE", "VARYING FORM OF TITLE"]
117
+ OM::Samples::ModsArticle.terminology.xpath_for(:title_info, :main_title)
118
+ => "//oxns:titleInfo/oxns:title"
119
+ ```
120
+
121
+ The solution: include the root node in your term pointer.
122
+
123
+ ```ruby
124
+ OM::Samples::ModsArticle.terminology.xpath_for(:mods, :title_info, :main_title)
125
+ => "//oxns:mods/oxns:titleInfo/oxns:title"
126
+ doc.term_values(:mods, :title_info, :main_title)
127
+ => ["ARTICLE TITLE", "VARYING FORM OF TITLE"]
128
+ ```
129
+
130
+ We can still access the Journal title by its own pointers:
131
+
132
+ ```ruby
133
+ doc.term_values(:journal, :title_info, :main_title)
134
+ => ["TITLE OF HOST JOURNAL"]
135
+ ```
136
+
137
+ ### Making life easier with Proxy Terms
138
+
139
+ If you use a nested term often, you may want to avoid typing the whole
140
+ sequence of term names by defining a *proxy* term.
141
+
142
+ As you can see in
143
+ [OM::Samples::ModsArticle](https://github.com/projecthydra/om/blob/master/lib/om/samples/mods_article.rb),
144
+ we have defined a few proxy terms for convenience.
145
+
146
+ ```ruby
147
+ t.publication_url(:proxy=>[:location,:url])
148
+ t.peer_reviewed(:proxy=>[:journal,:origin_info,:issuance], :index_as=>[:facetable])
149
+ t.title(:proxy=>[:mods,:title_info, :main_title])
150
+ t.journal_title(:proxy=>[:journal, :title_info, :main_title])
151
+ ```
152
+
153
+ You can use proxy terms just like any other term when querying the document.
154
+ ```ruby
155
+ OM::Samples::ModsArticle.terminology.xpath_for(:peer_reviewed)
156
+ => "//oxns:relatedItem[@type=\"host\"]/oxns:originInfo/oxns:issuance"
157
+ OM::Samples::ModsArticle.terminology.xpath_for(:title)
158
+ => "//oxns:mods/oxns:titleInfo/oxns:title"
159
+ OM::Samples::ModsArticle.terminology.xpath_for(:journal_title)
160
+ => "//oxns:relatedItem[@type=\"host\"]/oxns:titleInfo/oxns:title"
161
+ ```
162
+
data/README.md CHANGED
@@ -12,7 +12,7 @@ OM "terms" are ruby symbols you define (in the terminology) that map specific XM
12
12
  ## Tutorials & Reference
13
13
 
14
14
  * [Tame Your XML with OM](https://github.com/projecthydra/om/wiki/Tame-your-XML-with-OM)
15
- * [Common OM Patterns](https://github.com/projecthydra/om/blob/master/COMMON_OM_PATTERNS.textile)
15
+ * [Common OM Patterns](https://github.com/projecthydra/om/blob/master/COMMON_OM_PATTERNS.md)
16
16
 
17
17
  ### Solrizing Documents
18
18
 
@@ -28,7 +28,7 @@ We have a page on the Hydra wiki with a list of OM Terminologies in active use:
28
28
 
29
29
  ### Creator
30
30
 
31
- Matt Zumwalt ([MediaShelf](http://yourmediashelf.com)
31
+ Matt Zumwalt ([MediaShelf](http://yourmediashelf.com))
32
32
 
33
33
  ### Thanks To
34
34
 
@@ -0,0 +1,6 @@
1
+ ### Updating, Inserting & Deleting Elements ([TermValueOperators](http://ruby-doc.org/gems/docs/o/om-1.8.0/OM/XML/TermValueOperators.html))
2
+
3
+ ### Inserting Entire Hierarchies of Elements
4
+
5
+ TODO: write docs here.
6
+
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source "https://rubygems.org"
2
2
 
3
3
  gemspec :path=>"../"
4
4
 
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source "https://rubygems.org"
2
2
 
3
3
  gemspec :path=>"../"
4
4
 
@@ -1,3 +1,3 @@
1
1
  module Om
2
- VERSION = "3.1.0"
2
+ VERSION = "3.1.1"
3
3
  end
@@ -3,8 +3,8 @@ module OM
3
3
  #
4
4
  # Provides a natural syntax for using OM Terminologies to access values from xml Documents
5
5
  #
6
- # *Note*: All of these examples assume that @article is an instance of OM::Samples::ModsArticle. Look at that file to see the Terminology.
7
- #
6
+ # *Note*: All of these examples assume that @article is an instance of OM::Samples::ModsArticle. Look at that file to see the Terminology.
7
+ #
8
8
  # @example Return an array of the value(s) "start page" node(s) from the second issue node within the first journal node
9
9
  # # Using DynamicNode syntax:
10
10
  # @article.journal(0).issue(1).pages.start
@@ -38,37 +38,23 @@ module OM
38
38
  self.parent = parent
39
39
  end
40
40
 
41
- def method_missing (name, *args, &block)
42
- if /=$/.match(name.to_s)
43
- new_update_node(name, args)
44
- elsif args.length > 1
45
- new_update_node_with_index(name, args)
46
- else
47
- child = term_child_by_name(term.nil? ? parent.term : term, name)
48
- if child
49
- OM::XML::DynamicNode.new(name, args.first, @document, child, self)
50
- else
51
- val.send(name, *args, &block)
52
- end
53
- end
41
+ # In practice, method_missing will respond 4 different ways:
42
+ # (1) ALL assignment operations are accepted/attempted as new nodes,
43
+ # (2) ANY operation with multiple arguments is accepted/attempted as a new node (w/ index),
44
+ # (3) With an auto-constructed sub DynamicNode object,
45
+ # (4) By handing off to val. This is the only route that will return NoMethodError.
46
+ #
47
+ # Here we don't have args, so we cannot handle cases 2 and 3. But we can at least do 1 and 4.
48
+ def respond_to_missing?(name, include_private = false)
49
+ /=$/.match(name.to_s) || val.respond_to?(name, include_private) || super
54
50
  end
55
51
 
56
- def respond_to?(method)
57
- super || val.respond_to?(method)
58
- end
59
-
60
- def new_update_node(name, args)
61
- modified_name = name.to_s.chop.to_sym
62
- child = term.retrieve_term(modified_name)
63
- node = OM::XML::DynamicNode.new(modified_name, nil, @document, child, self)
64
- node.val=args
65
- end
66
-
67
- def new_update_node_with_index(name, args)
68
- index = args.shift
69
- child = term.retrieve_term(name)
70
- node = OM::XML::DynamicNode.new(name, index, @document, child, self)
71
- node.val=args
52
+ def method_missing(name, *args, &block)
53
+ return new_update_node(name.to_s.chop.to_sym, nil, args) if /=$/.match(name.to_s)
54
+ return new_update_node(name, args.shift, args) if args.length > 1
55
+ child = term_child_by_name(term.nil? ? parent.term : term, name)
56
+ return OM::XML::DynamicNode.new(name, args.first, @document, child, self) if child
57
+ val.send(name, *args, &block)
72
58
  end
73
59
 
74
60
  def val=(args)
@@ -96,18 +82,9 @@ module OM
96
82
  end
97
83
  end
98
84
 
99
-
100
- def term_child_by_name(term, name)
101
- if (term.kind_of? NamedTermProxy)
102
- @document.class.terminology.retrieve_node(*(term.proxy_pointer.dup << name))
103
- else
104
- term.retrieve_term(name)
105
- end
106
- end
107
-
108
85
  # This resolves the target of this dynamic node into a reified Array
109
86
  # @return [Array]
110
- def val
87
+ def val
111
88
  query = xpath
112
89
  trim_text = !query.index("text()").nil?
113
90
  val = @document.find_by_xpath(query).collect {|node| (trim_text ? node.text.strip : node.text) }
@@ -123,7 +100,7 @@ module OM
123
100
  def delete
124
101
  nodeset.delete
125
102
  end
126
-
103
+
127
104
  def inspect
128
105
  val.inspect
129
106
  end
@@ -146,7 +123,7 @@ module OM
146
123
  else ### A pointer
147
124
  parent.nil? ? [key] : parent.to_pointer << key
148
125
  end
149
- end
126
+ end
150
127
 
151
128
  def xpath
152
129
  if parent.nil?
@@ -155,10 +132,8 @@ module OM
155
132
  chain = retrieve_addressed_node( )
156
133
  '//' + chain.map { |n| n.xpath}.join('/')
157
134
  end
158
-
159
135
  end
160
136
 
161
-
162
137
  class AddressedNode
163
138
  attr_accessor :xpath, :key, :pointer
164
139
  def initialize (pointer, xpath, key)
@@ -167,15 +142,12 @@ module OM
167
142
  self.pointer = pointer
168
143
  end
169
144
  end
170
-
145
+
171
146
  ##
172
147
  # This is very similar to Terminology#retrieve_term, however it expands proxy paths out into their cannonical paths
173
148
  def retrieve_addressed_node()
174
149
  chain = []
175
-
176
- if parent
177
- chain += parent.retrieve_addressed_node()
178
- end
150
+ chain += parent.retrieve_addressed_node() if parent
179
151
  if (self.index)
180
152
  ### This is an index
181
153
  node = AddressedNode.new(key, term.xpath_relative, self)
@@ -191,12 +163,31 @@ module OM
191
163
  p = p.retrieve_term(first)
192
164
  chain << AddressedNode.new(p, p.xpath_relative, self)
193
165
  end
194
- else
166
+ else
195
167
  chain << AddressedNode.new(key, term.xpath_relative, self)
196
168
  end
197
169
  chain
198
170
  end
199
171
 
172
+ private
173
+
174
+ # Only to be called by method_missing, hence the NoMethodError.
175
+ # We know term.sanitize_new_values would fail in .val= if we pass a nil term.
176
+ def new_update_node(name, index, args)
177
+ child = term.retrieve_term(name)
178
+ raise NoMethodError, "undefined method `#{name}' in OM::XML::DynamicNode for #{self}:#{self.class}" if child.nil?
179
+ node = OM::XML::DynamicNode.new(name, index, @document, child, self)
180
+ node.val = args
181
+ end
182
+
183
+ # Only to be called by method_missing
184
+ def term_child_by_name(term, name)
185
+ if (term.kind_of? NamedTermProxy)
186
+ @document.class.terminology.retrieve_node(*(term.proxy_pointer.dup << name))
187
+ else
188
+ term.retrieve_term(name)
189
+ end
190
+ end
200
191
 
201
192
  end
202
193
  end
@@ -33,7 +33,7 @@ namespace :om do
33
33
  doc_destination = File.join(project_root, 'doc')
34
34
 
35
35
  YARD::Rake::YardocTask.new(:doc) do |yt|
36
- readme_filename = 'README.textile'
36
+ readme_filename = 'README.md'
37
37
  #yt.options = ['--private', '--protected', '--output-dir', doc_destination, '--readme', readme_filename]
38
38
  end
39
39
  rescue LoadError
data/om.gemspec CHANGED
@@ -9,6 +9,7 @@ Gem::Specification.new do |s|
9
9
  s.authors = ["Matt Zumwalt", "Justin Coyne"]
10
10
  s.email = %q{matt.zumwalt@yourmediashelf.com justin.coyne@mediashelf.com}
11
11
  s.homepage = %q{http://github.com/projecthydra/om}
12
+ s.license = 'APACHE2'
12
13
  s.summary = %q{OM (Opinionated Metadata): A library to help you tame sprawling XML schemas like MODS.}
13
14
  s.description = %q{OM (Opinionated Metadata): A library to help you tame sprawling XML schemas like MODS. Wraps Nokogiri documents in objects with miscellaneous helper methods for doing things like retrieve generated xpath queries or look up properties based on a simplified DSL}
14
15
 
@@ -21,8 +22,6 @@ Gem::Specification.new do |s|
21
22
  s.add_development_dependency "rspec", "~> 2.0"
22
23
  s.add_development_dependency "rake"
23
24
  s.add_development_dependency "yard"
24
- s.add_development_dependency "rdoc"
25
- s.add_development_dependency "RedCloth" # for textile formatting in rdoc
26
25
  s.add_development_dependency "awesome_print"
27
26
  s.add_development_dependency "equivalent-xml", ">= 0.2.4"
28
27
 
@@ -30,10 +30,10 @@ describe "use the root element as a member of the proxy address" do
30
30
  end
31
31
 
32
32
  it "should pull out all occurences of the_thing_we_want in the relevant_container" do
33
- subject.relevant_container.the_thing_we_want.should == ["1", "2"]
33
+ expect(subject.relevant_container.the_thing_we_want).to eq ["1", "2"]
34
34
  end
35
35
 
36
36
  it "should only pull out the_thing_we_want at the root level" do
37
- subject.the_thing_we_want.should == ["2"]
37
+ expect(subject.the_thing_we_want).to eq ["2"]
38
38
  end
39
39
  end
@@ -53,39 +53,39 @@ EOF
53
53
  end
54
54
 
55
55
  it "should handle single-element terms correctly" do
56
- subject.elementA.should == ["valA"]
56
+ expect(subject.elementA).to eq ["valA"]
57
57
  end
58
58
 
59
59
  it "should handle term paths" do
60
- subject.elC.should == ["valC"]
60
+ expect(subject.elC).to eq ["valC"]
61
61
  end
62
62
 
63
63
  it "should handle multiple-element, terms with paths correctly" do
64
- subject.elB.should == ["valB1", "valB2"]
64
+ expect(subject.elB).to eq ["valB1", "valB2"]
65
65
  end
66
66
 
67
67
  it "should handle terms that require specific attributes" do
68
- subject.elementC.should == ["valC"]
68
+ expect(subject.elementC).to eq ["valC"]
69
69
  end
70
70
 
71
71
  it "should handle" do
72
- subject.here.length.should == 1
73
- subject.here.first.split(/\W/).should include('123', '456')
72
+ expect(subject.here.length).to eq 1
73
+ expect(subject.here.first.split(/\W/)).to include('123', '456')
74
74
  end
75
75
 
76
76
  it "should handle missing terms" do
77
- subject.there.should be_empty
77
+ expect(subject.there).to be_empty
78
78
  end
79
79
 
80
80
  it "should handle element value given the absence of a specific attribute" do
81
- subject.elementD.should == ["valD1"]
82
- subject.no_attrib.should == ["valB1"]
81
+ expect(subject.elementD).to eq ["valD1"]
82
+ expect(subject.no_attrib).to eq ["valB1"]
83
83
  end
84
84
 
85
85
  it "should handle OM terms for an attribute value" do
86
- subject.elementB.my_attr.should == ["vole"]
87
- subject.alternate.should == ["vole"]
88
- subject.another.should == ["vole"]
89
- subject.animal_attrib.should include("vole", "seagull")
86
+ expect(subject.elementB.my_attr).to eq ["vole"]
87
+ expect(subject.alternate).to eq ["vole"]
88
+ expect(subject.another).to eq ["vole"]
89
+ expect(subject.animal_attrib).to include("vole", "seagull")
90
90
  end
91
91
  end