om 1.6.0 → 1.6.1
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/COMMON_OM_PATTERNS.textile +13 -1
- data/Gemfile +7 -4
- data/Gemfile.lock +19 -14
- data/History.textile +4 -0
- data/lib/om/version.rb +1 -1
- data/lib/om/xml/document.rb +16 -2
- data/lib/om/xml/terminology.rb +5 -0
- data/lib/tasks/om.rake +16 -10
- data/om.gemspec +1 -0
- data/spec/fixtures/mods_articles/hydrangea_article1.xml +7 -0
- data/spec/integration/differentiated_elements_spec.rb +39 -0
- data/spec/integration/element_value_spec.rb +91 -0
- data/spec/integration/proxies_and_ref_spec.rb +81 -0
- data/spec/integration/querying_documents_spec.rb +73 -0
- data/spec/integration/rights_metadata_integration_example_spec.rb +2 -4
- data/spec/integration/selective_querying_spec.rb +89 -0
- data/spec/integration/set_reentrant_terminology_spec.rb +134 -0
- data/spec/integration/xpathy_stuff_spec.rb +204 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/unit/container_spec.rb +2 -4
- data/spec/unit/document_spec.rb +2 -3
- data/spec/unit/dynamic_node_spec.rb +1 -2
- data/spec/unit/named_term_proxy_spec.rb +1 -2
- data/spec/unit/node_generator_spec.rb +2 -3
- data/spec/unit/nokogiri_sanity_spec.rb +2 -3
- data/spec/unit/om_spec.rb +2 -4
- data/spec/unit/template_registry_spec.rb +1 -2
- data/spec/unit/term_builder_spec.rb +2 -3
- data/spec/unit/term_spec.rb +1 -2
- data/spec/unit/term_value_operators_spec.rb +2 -3
- data/spec/unit/term_xpath_generator_spec.rb +1 -2
- data/spec/unit/terminology_builder_spec.rb +1 -2
- data/spec/unit/terminology_spec.rb +1 -2
- data/spec/unit/validation_spec.rb +2 -4
- data/spec/unit/xml_serialization_spec.rb +2 -4
- data/spec/unit/xml_spec.rb +2 -4
- metadata +68 -13
@@ -0,0 +1,89 @@
|
|
1
|
+
# These tests illustrate how to select nodes based on their position
|
2
|
+
# within an XML hierarchy and the value of particular attributes.
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
|
6
|
+
describe "Selecting nodes based on (a) position in hierarchy and (b) attributes" do
|
7
|
+
|
8
|
+
before(:all) do
|
9
|
+
|
10
|
+
# Some XML, with various flavors of <note> nodes:
|
11
|
+
# - outer vs inner;
|
12
|
+
# - with vs without an "a" attribute.
|
13
|
+
@xml = %Q{
|
14
|
+
<root xmlns="foo">
|
15
|
+
<note>o1</note>
|
16
|
+
<note>o2</note>
|
17
|
+
<note a="a">o3a</note>
|
18
|
+
<note a="a">o4a</note>
|
19
|
+
<inner>
|
20
|
+
<note>i1</note>
|
21
|
+
<note>i2</note>
|
22
|
+
<note a="a">i3a</note>
|
23
|
+
<note a="a">i4a</note>
|
24
|
+
</inner>
|
25
|
+
</root>
|
26
|
+
}
|
27
|
+
|
28
|
+
# Our document class and its OM terminology.
|
29
|
+
#
|
30
|
+
# In order to select only the outer or inner <note> nodes, we must use
|
31
|
+
# the :proxy approach shown below; however, that approach does not work
|
32
|
+
# with :attributes. Thus, the general strategy here is first to define OM
|
33
|
+
# terms for any attibute-based selections we might want, and then to
|
34
|
+
# refine those further using :proxy.
|
35
|
+
class FooDoc
|
36
|
+
include OM::XML::Document
|
37
|
+
|
38
|
+
set_terminology do |t|
|
39
|
+
t.root :path => 'root', :xmlns => 'foo'
|
40
|
+
|
41
|
+
# All notes.
|
42
|
+
t.note
|
43
|
+
t.all_note :path => 'note' # Included for symmetry.
|
44
|
+
|
45
|
+
# All notes with and without attributes.
|
46
|
+
t.all_note_a :path => 'note', :attributes => { :a => "a" }
|
47
|
+
t.all_note_not_a :path => 'note', :attributes => { :a => :none }
|
48
|
+
|
49
|
+
# All inner notes -- again, with and without attributes.
|
50
|
+
t.inner do
|
51
|
+
t.note
|
52
|
+
t.note_a :path => 'note', :attributes => { :a => "a" }
|
53
|
+
t.note_not_a :path => 'note', :attributes => { :a => :none }
|
54
|
+
end
|
55
|
+
|
56
|
+
# Using the terms defined above, we can now define any additional
|
57
|
+
# selections we might need.
|
58
|
+
t.all_outer_note :proxy => [:root, :note]
|
59
|
+
t.all_inner_note :proxy => [:root, :inner, :note]
|
60
|
+
t.outer_note_a :proxy => [:root, :all_note_a]
|
61
|
+
t.outer_note_not_a :proxy => [:root, :all_note_not_a]
|
62
|
+
t.inner_note_a :proxy => [:root, :inner, :note_a]
|
63
|
+
t.inner_note_not_a :proxy => [:root, :inner, :note_not_a]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# A document instance.
|
68
|
+
@doc = FooDoc.from_xml(@xml)
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
# Did it work?
|
73
|
+
it "should be able to select all types of <note> nodes" do
|
74
|
+
tests = [
|
75
|
+
# OM term. Expected result.
|
76
|
+
[ 'all_note', %w(o1 o2 o3a o4a i1 i2 i3a i4a) ],
|
77
|
+
[ 'all_note_a', %w( o3a o4a i3a i4a) ],
|
78
|
+
[ 'all_note_not_a', %w(o1 o2 i1 i2 ) ],
|
79
|
+
[ 'all_outer_note', %w(o1 o2 o3a o4a ) ],
|
80
|
+
[ 'all_inner_note', %w( i1 i2 i3a i4a) ],
|
81
|
+
[ 'outer_note_a', %w( o3a o4a ) ],
|
82
|
+
[ 'outer_note_not_a', %w(o1 o2 ) ],
|
83
|
+
[ 'inner_note_a', %w( i3a i4a) ],
|
84
|
+
[ 'inner_note_not_a', %w( i1 i2 ) ],
|
85
|
+
]
|
86
|
+
tests.each { |meth, exp| @doc.send(meth).should == exp }
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "calling set_terminology more than once" do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
class ReentrantTerminology
|
7
|
+
include OM::XML::Document
|
8
|
+
|
9
|
+
set_terminology do |t|
|
10
|
+
t.root :path => 'root', :xmlns => "asdf"
|
11
|
+
t.foo
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "before" do
|
17
|
+
|
18
|
+
subject do
|
19
|
+
xml = '<root xmlns="asdf"><foo>fooval</foo><bar>barval</bar></root>'
|
20
|
+
ReentrantTerminology.from_xml(xml)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "can get foo" do
|
24
|
+
subject.foo.should == ['fooval']
|
25
|
+
end
|
26
|
+
|
27
|
+
it "cannot get bar" do
|
28
|
+
expect { subject.bar }.to raise_error OM::XML::Terminology::BadPointerError
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "after" do
|
34
|
+
|
35
|
+
before(:all) do
|
36
|
+
class ReentrantTerminology
|
37
|
+
set_terminology do |t|
|
38
|
+
t.root :path => 'root', :xmlns => "asdf"
|
39
|
+
t.bar
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
subject do
|
45
|
+
xml = '<root xmlns="asdf"><foo>fooval</foo><bar>barval</bar></root>'
|
46
|
+
ReentrantTerminology.from_xml(xml)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "cannot get foo" do
|
50
|
+
expect { subject.foo }.to raise_error OM::XML::Terminology::BadPointerError
|
51
|
+
end
|
52
|
+
|
53
|
+
it "can now get bar" do
|
54
|
+
subject.bar.should == ['barval']
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "re-entrant modification" do
|
60
|
+
|
61
|
+
|
62
|
+
before(:all) do
|
63
|
+
class ReentrantTerminology
|
64
|
+
set_terminology do |t|
|
65
|
+
t.root :path => 'root', :xmlns => "asdf"
|
66
|
+
t.foo
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class ReentrantTerminology
|
71
|
+
extend_terminology do |t|
|
72
|
+
t.bar
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
subject do
|
78
|
+
xml = '<root xmlns="asdf"><foo>fooval</foo><bar>barval</bar></root>'
|
79
|
+
ReentrantTerminology.from_xml(xml)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "can get foo" do
|
83
|
+
subject.foo.should == ['fooval']
|
84
|
+
end
|
85
|
+
|
86
|
+
it "can get bar" do
|
87
|
+
subject.bar.should == ['barval']
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "subclass modification" do
|
93
|
+
|
94
|
+
|
95
|
+
before(:all) do
|
96
|
+
class ReentrantTerminology
|
97
|
+
set_terminology do |t|
|
98
|
+
t.root :path => 'root', :xmlns => "asdf"
|
99
|
+
t.foo
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class LocalReentrantTerminology
|
104
|
+
include OM::XML::Document
|
105
|
+
use_terminology(ReentrantTerminology)
|
106
|
+
extend_terminology do |t|
|
107
|
+
t.bar
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
subject do
|
113
|
+
xml = '<root xmlns="asdf"><foo>fooval</foo><bar>barval</bar></root>'
|
114
|
+
LocalReentrantTerminology.from_xml(xml)
|
115
|
+
end
|
116
|
+
|
117
|
+
it "shouldn't bleed up the inheritence stack" do
|
118
|
+
xml = '<root xmlns="asdf"><foo>fooval</foo><bar>barval</bar></root>'
|
119
|
+
t = ReentrantTerminology.from_xml(xml)
|
120
|
+
|
121
|
+
expect { t.bar }.to raise_error OM::XML::Terminology::BadPointerError
|
122
|
+
end
|
123
|
+
|
124
|
+
it "can get foo" do
|
125
|
+
subject.foo.should == ['fooval']
|
126
|
+
end
|
127
|
+
|
128
|
+
it "can get bar" do
|
129
|
+
subject.bar.should == ['barval']
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "an example of xpath-y stuff, also using :proxy and :ref and namespaces" do
|
4
|
+
|
5
|
+
describe "a contrived example" do
|
6
|
+
before(:all) do
|
7
|
+
class XpathyStuffTerminology
|
8
|
+
include OM::XML::Document
|
9
|
+
|
10
|
+
set_terminology do |t|
|
11
|
+
t.root(:path=>"contentMetadata", :xmlns => '', :namespace_prefix => nil)
|
12
|
+
|
13
|
+
t.resource(:namespace_prefix => nil) {
|
14
|
+
t.file(:ref=>[:file], :namespace_prefix => nil)
|
15
|
+
}
|
16
|
+
|
17
|
+
t.file(:namespace_prefix => nil) {
|
18
|
+
t.location(:path=>"location", :namespace_prefix => nil)
|
19
|
+
t.filename(:path=>{:attribute=>"id"}, :namespace_prefix => nil)
|
20
|
+
t.format(:path=>{:attribute=>"format"}, :namespace_prefix => nil)
|
21
|
+
}
|
22
|
+
t.content(:ref=>:file, :path=>'resource/file[location="content"]', :namespace_prefix => nil)
|
23
|
+
t.html(:ref=>:file, :path=>'resource/file[location="html"]', :namespace_prefix => nil)
|
24
|
+
|
25
|
+
t.content_location(:proxy=>[:content, :location])
|
26
|
+
t.content_filename(:proxy=>[:content, :filename])
|
27
|
+
t.content_format(:proxy=>[:content, :format])
|
28
|
+
|
29
|
+
t.html_location(:proxy=>[:html, :location])
|
30
|
+
t.html_filename(:proxy=>[:html, :filename])
|
31
|
+
t.html_format(:proxy=>[:html, :format])
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
subject do
|
38
|
+
XpathyStuffTerminology.from_xml <<-EOF
|
39
|
+
<contentMetadata>
|
40
|
+
<resource type="file" id="BU3A5" objectId="val2">
|
41
|
+
<file id="BURCH1" format="BINARY">
|
42
|
+
<location>content</location>
|
43
|
+
</file>
|
44
|
+
<file id="BURCH1.html" format="HTML">
|
45
|
+
<location>html</location>
|
46
|
+
</file>
|
47
|
+
</resource>
|
48
|
+
</contentMetadata>
|
49
|
+
|
50
|
+
EOF
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should have a content term" do
|
54
|
+
subject.content.first.should =~ /content/
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should have an html term" do
|
58
|
+
subject.html.first.should =~ /html/
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "an example from MODS" do
|
65
|
+
before(:all) do
|
66
|
+
class ModsXpathyStuffTerminology
|
67
|
+
include OM::XML::Document
|
68
|
+
|
69
|
+
set_terminology do |t|
|
70
|
+
t.root(:path=>"mods", :xmlns=>"http://www.loc.gov/mods/v3")
|
71
|
+
t.person(:path=>"name", :namespace_prefix => nil) {
|
72
|
+
t.given(:path=>"namePart", :attributes=>{:type=>"given"})
|
73
|
+
t.family(:path=>"namePart", :attributes=>{:type=>"family"})
|
74
|
+
t.role(:namespace_prefix => nil) {
|
75
|
+
t.text(:path=>"roleTerm", :attributes=>{:type=>"text"})
|
76
|
+
t.code(:path=>"roleTerm", :attributes=>{:type=>"code"})
|
77
|
+
}
|
78
|
+
}
|
79
|
+
t.author(:ref=>:person, :path=>'name[./role/roleTerm="aut"]')
|
80
|
+
t.advisor(:ref=>:person, :path=>'name[./role/roleTerm="ths"]')
|
81
|
+
|
82
|
+
t.author_given(:proxy=>[:author, :given])
|
83
|
+
t.author_family(:proxy=>[:author, :family])
|
84
|
+
t.advisor_given(:proxy=>[:advisor, :given])
|
85
|
+
t.advisor_family(:proxy=>[:advisor, :family])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
subject do
|
91
|
+
ModsXpathyStuffTerminology.from_xml <<-EOF
|
92
|
+
<mods xmlns="http://www.loc.gov/mods/v3"
|
93
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3"
|
94
|
+
xsi:schemaLocation="http://www.loc.gov/mods/v3
|
95
|
+
http://www.loc.gov/standards/mods/v3/mods-3-3.xsd">
|
96
|
+
<name type="personal">
|
97
|
+
<namePart type="given">Mary</namePart>
|
98
|
+
<namePart type="family">Pickral</namePart>
|
99
|
+
<affiliation>University of Virginia</affiliation>
|
100
|
+
<namePart>mpc3c</namePart>
|
101
|
+
<affiliation>University of Virginia Library</affiliation>
|
102
|
+
<role>
|
103
|
+
<roleTerm authority="marcrelator" type="code">aut</roleTerm>
|
104
|
+
<roleTerm authority="marcrelator" type="text">author</roleTerm>
|
105
|
+
</role>
|
106
|
+
</name>
|
107
|
+
<name type="personal">
|
108
|
+
<namePart>der5y</namePart>
|
109
|
+
<namePart type="given">David</namePart>
|
110
|
+
<namePart type="family">Jones</namePart>
|
111
|
+
<affiliation>University of Virginia</affiliation>
|
112
|
+
<affiliation>Architectural History Dept.</affiliation>
|
113
|
+
<role>
|
114
|
+
<roleTerm authority="marcrelator" type="code">ths</roleTerm>
|
115
|
+
<roleTerm authority="marcrelator" type="text">advisor</roleTerm>
|
116
|
+
</role>
|
117
|
+
</name>
|
118
|
+
</mods>
|
119
|
+
EOF
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should have the terms :author_given and :author_family to get the author name" do
|
123
|
+
pending "This doesn't seem to work?"
|
124
|
+
subject.author_given.should include("Mary")
|
125
|
+
subject.author_family.should include("Pickral")
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should have the terms :advisor_given and :advisor_family to get the advisor name" do
|
129
|
+
pending "This doesn't seem to work?"
|
130
|
+
subject.advisor_given.should include("David")
|
131
|
+
subject.advisor_family.should include("Small")
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
describe "more MODS examples, with a given namespace prefix?" do
|
137
|
+
|
138
|
+
before(:all) do
|
139
|
+
class ModsXpathyStuffTerminology
|
140
|
+
include OM::XML::Document
|
141
|
+
|
142
|
+
set_terminology do |t|
|
143
|
+
t.root(:path=>"mods", :xmlns=>"http://www.loc.gov/mods/v3", :schema=>"http://www.loc.gov/standards/mods/v3/mods-3-3.xsd", :namespace_prefix => "mods")
|
144
|
+
|
145
|
+
t.name_ {
|
146
|
+
t.name_part(:path=>"namePart")
|
147
|
+
t.family_name(:path=>"namePart", :attributes=>{:type=>"family"})
|
148
|
+
t.given_name(:path=>"namePart", :attributes=>{:type=>"given"}, :label=>"first name")
|
149
|
+
t.terms_of_address(:path=>"namePart", :attributes=>{:type=>"termsOfAddress"})
|
150
|
+
t.role(:ref=>[:role])
|
151
|
+
}
|
152
|
+
t.role {
|
153
|
+
t.role_term_text(:path=>"roleTerm", :attributes=>{:type=>"text"})
|
154
|
+
}
|
155
|
+
|
156
|
+
t.person_full(:ref=>:name, :attributes=>{:type=>"personal"})
|
157
|
+
t.person(:proxy=>[:person_full, :name_part])
|
158
|
+
t.creator(:ref=>:person, :path=>'name[mods:role/mods:roleTerm="creator"]', :xmlns=>"http://www.loc.gov/mods/v3", :namespace_prefix => "mods")
|
159
|
+
|
160
|
+
t.corporate_full(:ref=>:name, :attributes=>{:type=>"corporate"})
|
161
|
+
t.corporate(:proxy=>[:corporate_full, :name_part])
|
162
|
+
t.repository(:ref=>:corporate, :path=>'name[mods:role/mods:roleTerm="repository"]', :xmlns=>"http://www.loc.gov/mods/v3", :namespace_prefix => "mods")
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
subject do
|
168
|
+
ModsXpathyStuffTerminology.from_xml <<-EOF
|
169
|
+
<mods:mods xmlns:mods="http://www.loc.gov/mods/v3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3" xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-3.xsd">
|
170
|
+
|
171
|
+
<mods:name type="personal">
|
172
|
+
<mods:namePart>David Small</mods:namePart>
|
173
|
+
<mods:role>
|
174
|
+
<mods:roleTerm authority="marcrelator" type="text">creator</mods:roleTerm>
|
175
|
+
</mods:role>
|
176
|
+
</mods:name>
|
177
|
+
<mods:name type="corporate">
|
178
|
+
<mods:namePart>Graphic Novel Repository</mods:namePart>
|
179
|
+
<mods:role>
|
180
|
+
<mods:roleTerm authority="local" type="text">repository</mods:roleTerm>
|
181
|
+
</mods:role>
|
182
|
+
</mods:name>
|
183
|
+
</mods:mods>
|
184
|
+
EOF
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should give a creator value" do
|
188
|
+
subject.creator.should include "David Small"
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should give a repository value" do
|
192
|
+
subject.repository.should include "Graphic Novel Repository"
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should have a person term 'for more generic xml'" do
|
196
|
+
subject.person.should include "David Small"
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should have a corporate term 'for more generic xml'" do
|
200
|
+
subject.corporate.should include "Graphic Novel Repository"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
if ENV['COVERAGE'] and RUBY_VERSION =~ /^1.9/
|
2
|
+
require 'simplecov'
|
3
|
+
require 'simplecov-rcov'
|
4
|
+
|
5
|
+
SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
|
6
|
+
SimpleCov.start
|
7
|
+
end
|
8
|
+
|
1
9
|
require 'om'
|
2
10
|
require 'rspec'
|
3
11
|
require 'equivalent-xml/rspec_matchers'
|