opinionated-xml 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/om.rb +9 -0
- data/lib/om/xml.rb +23 -0
- data/lib/om/xml/accessors.rb +130 -0
- data/lib/om/xml/container.rb +32 -0
- data/lib/{opinionated-xml/ox.rb → om/xml/properties.rb} +10 -60
- data/lib/om/xml/property_value_operators.rb +111 -0
- data/lib/om/xml/validation.rb +63 -0
- data/opinionated-xml.gemspec +26 -14
- data/spec/fixtures/RUBRIC_mods_article_template.xml +89 -0
- data/spec/fixtures/mods_articles/hydrangea_article1.xml +90 -0
- data/spec/fixtures/test_dummy_mods.xml +17 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/unit/accessors_spec.rb +156 -0
- data/spec/unit/container_spec.rb +60 -0
- data/spec/unit/{opinionated-xml_spec.rb → properties_spec.rb} +13 -66
- data/spec/unit/property_value_operators_spec.rb +245 -0
- data/spec/unit/validation_spec.rb +78 -0
- data/spec/unit/xml_spec.rb +21 -0
- metadata +40 -13
- data/lib/opinionated-xml.rb +0 -9
- data/lib/opinionated-xml/ox_property_values_helper.rb +0 -62
- data/spec/helpers/ox_property_values_helper_spec.rb +0 -55
- data/spec/unit/ox_integration_spec.rb +0 -124
@@ -0,0 +1,60 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require "nokogiri"
|
3
|
+
require "om"
|
4
|
+
|
5
|
+
describe "OM::XML::Container" do
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
class ContainerTest
|
9
|
+
include OM::XML::Container
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
@container = ContainerTest.from_xml("<foo><bar>1</bar></foo>")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should automatically include the other modules" do
|
18
|
+
pending
|
19
|
+
ContainerTest.included_modules.should include(OM::XML::Accessor)
|
20
|
+
ContainerTest.included_modules.should include(OM::XML::Schema)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should add .ng_xml accessor" do
|
24
|
+
@container.should respond_to(:ng_xml)
|
25
|
+
@container.should respond_to(:ng_xml=)
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "new" do
|
29
|
+
it "should populate ng_xml with an instance of Nokogiri::XML::Document" do
|
30
|
+
@container.ng_xml.class.should == Nokogiri::XML::Document
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#from_xml" do
|
35
|
+
it "should accept a String, parse it and store it in .ng_xml" do
|
36
|
+
Nokogiri::XML::Document.expects(:parse).returns("parsed xml")
|
37
|
+
container1 = ContainerTest.from_xml("<foo><bar>1</bar></foo>")
|
38
|
+
container1.ng_xml.should == "parsed xml"
|
39
|
+
end
|
40
|
+
it "should accept a File, parse it and store it in .ng_xml" do
|
41
|
+
file = fixture(File.join("mods_articles", "hydrangea_article1.xml"))
|
42
|
+
Nokogiri::XML::Document.expects(:parse).returns("parsed xml")
|
43
|
+
container1 = ContainerTest.from_xml(file)
|
44
|
+
container1.ng_xml.should == "parsed xml"
|
45
|
+
end
|
46
|
+
it "should accept Nokogiri nodes as input and leave them as-is" do
|
47
|
+
parsed_xml = Nokogiri::XML::Document.parse("<foo><bar>1</bar></foo>")
|
48
|
+
container1 = ContainerTest.from_xml(parsed_xml)
|
49
|
+
container1.ng_xml.should == parsed_xml
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe ".to_xml" do
|
54
|
+
it "should call .ng_xml.to_xml" do
|
55
|
+
@container.ng_xml.expects(:to_xml).returns("ng xml")
|
56
|
+
@container.to_xml.should == "ng xml"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -1,12 +1,14 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require "om"
|
2
3
|
|
3
|
-
describe "
|
4
|
+
describe "OM::XML::Properties" do
|
4
5
|
|
5
6
|
before(:all) do
|
6
7
|
#ModsHelpers.name_("Beethoven, Ludwig van", :date=>"1770-1827", :role=>"creator")
|
7
|
-
class FakeOxMods
|
8
|
-
|
9
|
-
include
|
8
|
+
class FakeOxMods
|
9
|
+
|
10
|
+
include OM::XML::Container
|
11
|
+
include OM::XML::Properties
|
10
12
|
|
11
13
|
# Could add support for multiple root declarations.
|
12
14
|
# For now, assume that any modsCollections have already been broken up and fed in as individual mods documents
|
@@ -40,8 +42,8 @@ describe "OpinionatedXml" do
|
|
40
42
|
|
41
43
|
class FakeOtherOx < Nokogiri::XML::Document
|
42
44
|
|
43
|
-
include
|
44
|
-
extend OX::ClassMethods
|
45
|
+
include OM::XML::Properties
|
46
|
+
# extend OX::ClassMethods
|
45
47
|
|
46
48
|
root_property :other, "other", "http://www.foo.com"
|
47
49
|
|
@@ -50,7 +52,7 @@ describe "OpinionatedXml" do
|
|
50
52
|
end
|
51
53
|
|
52
54
|
before(:each) do
|
53
|
-
@fixturemods = FakeOxMods.
|
55
|
+
@fixturemods = FakeOxMods.from_xml( fixture( File.join("CBF_MODS", "ARS0025_016.xml") ) )
|
54
56
|
end
|
55
57
|
|
56
58
|
after(:all) do
|
@@ -68,7 +70,6 @@ describe "OpinionatedXml" do
|
|
68
70
|
FakeOxMods.root_property_ref.should == :mods
|
69
71
|
FakeOxMods.root_config.should == {:ref=>:mods, :path=>"mods", :namespace=>"http://www.loc.gov/mods/v3", :attributes=>["id", "version"], :schema=>"http://www.loc.gov/standards/mods/v3/mods-3-2.xsd"}
|
70
72
|
FakeOxMods.ox_namespaces.should == {"oxns"=>"http://www.loc.gov/mods/v3"}
|
71
|
-
FakeOxMods.schema_url.should == "http://www.loc.gov/standards/mods/v3/mods-3-2.xsd"
|
72
73
|
|
73
74
|
FakeOtherOx.root_property_ref.should == :other
|
74
75
|
FakeOtherOx.root_config.should == {:namespace=>"http://www.foo.com", :path=>"other", :ref=>:other}
|
@@ -135,16 +136,16 @@ describe "OpinionatedXml" do
|
|
135
136
|
describe ".lookup" do
|
136
137
|
|
137
138
|
it "uses the generated xpath queries" do
|
138
|
-
@fixturemods.expects(:xpath).with('//oxns:name[@type="personal"]', @fixturemods.ox_namespaces)
|
139
|
+
@fixturemods.ng_xml.expects(:xpath).with('//oxns:name[@type="personal"]', @fixturemods.ox_namespaces)
|
139
140
|
@fixturemods.lookup(:person)
|
140
141
|
|
141
|
-
@fixturemods.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:namePart, "Beethoven, Ludwig van")]', @fixturemods.ox_namespaces)
|
142
|
+
@fixturemods.ng_xml.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:namePart, "Beethoven, Ludwig van")]', @fixturemods.ox_namespaces)
|
142
143
|
@fixturemods.lookup(:person, "Beethoven, Ludwig van")
|
143
144
|
|
144
|
-
@fixturemods.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "2010")]', @fixturemods.ox_namespaces)
|
145
|
+
@fixturemods.ng_xml.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "2010")]', @fixturemods.ox_namespaces)
|
145
146
|
@fixturemods.lookup(:person, :date=>"2010")
|
146
147
|
|
147
|
-
@fixturemods.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:role/oxns:roleTerm, "donor")]', @fixturemods.ox_namespaces)
|
148
|
+
@fixturemods.ng_xml.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:role/oxns:roleTerm, "donor")]', @fixturemods.ox_namespaces)
|
148
149
|
@fixturemods.lookup(:person, :role=>"donor")
|
149
150
|
|
150
151
|
# @fixturemods.expects(:xpath).with('//oxns:name[@type="personal"]/oxns:namePart[@type="date"]', @fixturemods.ox_namespaces)
|
@@ -242,59 +243,5 @@ describe "OpinionatedXml" do
|
|
242
243
|
FakeOxMods.send(:applicable_attributes, ["authority", {:type=>["text","code"]}] ).should == {:type=>"text"}
|
243
244
|
end
|
244
245
|
end
|
245
|
-
|
246
|
-
## Validation Support
|
247
|
-
# Some of these tests fail when you don't have an internet connection because the mods schema includes other xsd schemas by URL reference.
|
248
|
-
|
249
|
-
describe "#schema" do
|
250
|
-
it "should return an instance of Nokogiri::XML::Schema loaded from the schema url -- fails if no internet connection" do
|
251
|
-
FakeOxMods.schema.should be_kind_of Nokogiri::XML::Schema
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
describe "#validate" do
|
256
|
-
it "should validate the provided document against the schema provided in class definition -- fails if no internet connection" do
|
257
|
-
FakeOxMods.schema.expects(:validate).with(@fixturemods).returns([])
|
258
|
-
FakeOxMods.validate(@fixturemods)
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
describe ".validate" do
|
263
|
-
it "should rely on class validate method" do
|
264
|
-
FakeOxMods.expects(:validate).with(@fixturemods)
|
265
|
-
@fixturemods.validate
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
describe "#schema_file" do
|
270
|
-
before(:all) do
|
271
|
-
FakeOxMods.schema_file = nil
|
272
|
-
end
|
273
|
-
|
274
|
-
after(:all) do
|
275
|
-
FakeOxMods.schema_file = fixture("mods-3-2.xsd")
|
276
|
-
end
|
277
|
-
|
278
|
-
it "should lazy load the schema file from the @schema_url" do
|
279
|
-
FakeOxMods.instance_variable_get(:@schema_file).should be_nil
|
280
|
-
FakeOxMods.expects(:file_from_url).with(FakeOxMods.schema_url).returns("fake file").once
|
281
|
-
FakeOxMods.schema_file
|
282
|
-
FakeOxMods.instance_variable_get(:@schema_file).should == "fake file"
|
283
|
-
FakeOxMods.schema_file.should == "fake file"
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
|
-
describe "#file_from_url" do
|
288
|
-
it "should retrieve a file from the provided url over HTTP" do
|
289
|
-
FakeOxMods.send(:file_from_url, "http://google.com")
|
290
|
-
end
|
291
|
-
it "should raise an error if the url is invalid" do
|
292
|
-
lambda {FakeOxMods.send(:file_from_url, "")}.should raise_error(RuntimeError, "Could not retrieve file from . Error: No such file or directory - ")
|
293
|
-
lambda {FakeOxMods.send(:file_from_url, "foo")}.should raise_error(RuntimeError, "Could not retrieve file from foo. Error: No such file or directory - foo")
|
294
|
-
end
|
295
|
-
it "should raise an error if file retrieval fails" do
|
296
|
-
lambda {FakeOxMods.send(:file_from_url, "http://fedora-commons.org/nonexistent_file")}.should raise_error(RuntimeError, "Could not retrieve file from http://fedora-commons.org/nonexistent_file. Error: 404 Not Found")
|
297
|
-
end
|
298
|
-
end
|
299
246
|
|
300
247
|
end
|
@@ -0,0 +1,245 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require "om"
|
3
|
+
|
4
|
+
describe "OM::XML::PropertyValueOperators" do
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
#ModsHelpers.name_("Beethoven, Ludwig van", :date=>"1770-1827", :role=>"creator")
|
8
|
+
class PropertiesValueOperatorsTest
|
9
|
+
|
10
|
+
include OM::XML::Container
|
11
|
+
include OM::XML::Properties
|
12
|
+
include OM::XML::PropertyValueOperators
|
13
|
+
|
14
|
+
# Could add support for multiple root declarations.
|
15
|
+
# For now, assume that any modsCollections have already been broken up and fed in as individual mods documents
|
16
|
+
# root :mods_collection, :path=>"modsCollection",
|
17
|
+
# :attributes=>[],
|
18
|
+
# :subelements => :mods
|
19
|
+
|
20
|
+
root_property :mods, "mods", "http://www.loc.gov/mods/v3", :attributes=>["id", "version"], :schema=>"http://www.loc.gov/standards/mods/v3/mods-3-2.xsd"
|
21
|
+
|
22
|
+
|
23
|
+
property :name_, :path=>"name",
|
24
|
+
:attributes=>[:xlink, :lang, "xml:lang", :script, :transliteration, {:type=>["personal", "enumerated", "corporate"]} ],
|
25
|
+
:subelements=>["namePart", "displayForm", "affiliation", :role, "description"],
|
26
|
+
:default_content_path => "namePart",
|
27
|
+
:convenience_methods => {
|
28
|
+
:date => {:path=>"namePart", :attributes=>{:type=>"date"}},
|
29
|
+
:family_name => {:path=>"namePart", :attributes=>{:type=>"family"}},
|
30
|
+
:given_name => {:path=>"namePart", :attributes=>{:type=>"given"}},
|
31
|
+
:terms_of_address => {:path=>"namePart", :attributes=>{:type=>"termsOfAddress"}}
|
32
|
+
}
|
33
|
+
|
34
|
+
property :person, :variant_of=>:name_, :attributes=>{:type=>"personal"}
|
35
|
+
|
36
|
+
property :role, :path=>"role",
|
37
|
+
:parents=>[:name_],
|
38
|
+
:attributes=>[ { "type"=>["text", "code"] } , "authority"],
|
39
|
+
:default_content_path => "roleTerm"
|
40
|
+
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
before(:each) do
|
47
|
+
@sample = PropertiesValueOperatorsTest.from_xml( fixture( File.join("test_dummy_mods.xml") ) )
|
48
|
+
end
|
49
|
+
|
50
|
+
after(:all) do
|
51
|
+
Object.send(:remove_const, :PropertiesValueOperatorsTest)
|
52
|
+
end
|
53
|
+
|
54
|
+
describe ".property_values" do
|
55
|
+
|
56
|
+
it "should call .lookup and then build an array of values from the returned nodeset (using default_node, etc as nessesary)" do
|
57
|
+
lookup_opts = "insert args here"
|
58
|
+
mock_node = mock("node")
|
59
|
+
mock_node.expects(:text).returns("sample value").times(3)
|
60
|
+
mock_nodeset = [mock_node, mock_node, mock_node]
|
61
|
+
@sample.expects(:lookup).with(lookup_opts).returns(mock_nodeset)
|
62
|
+
|
63
|
+
@sample.property_values(lookup_opts).should == ["sample value","sample value","sample value"]
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
describe ".property_values_append" do
|
69
|
+
|
70
|
+
it "looks up the parent using :parent_select, uses :child_index to choose the parent node from the result set, uses :template to build the node(s) to be inserted, inserts the :values(s) into the node(s) and adds the node(s) to the parent" do
|
71
|
+
@sample.property_values_append(
|
72
|
+
:parent_select => [:person, {:given_name=>"Tim", :family_name=>"Berners-Lee"}] ,
|
73
|
+
:child_index => :first,
|
74
|
+
:template => [:person, :affiliation],
|
75
|
+
:values => ["my new value", "another new value"]
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should accept parent_select and template [property_reference, lookup_opts] as argument arrays for generators/lookups" do
|
80
|
+
# this appends two affiliation nodes into the first person node whose name is Tim Berners-Lee
|
81
|
+
expected_result = '<ns3:name type="personal">
|
82
|
+
<ns3:namePart type="family">Berners-Lee</ns3:namePart>
|
83
|
+
<ns3:namePart type="given">Tim</ns3:namePart>
|
84
|
+
<ns3:role>
|
85
|
+
<ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
|
86
|
+
<ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
|
87
|
+
</ns3:role>
|
88
|
+
<ns3:affiliation>my new value</ns3:affiliation><ns3:affiliation>another new value</ns3:affiliation></ns3:name>'
|
89
|
+
|
90
|
+
@sample.property_values_append(
|
91
|
+
:parent_select => [:person, {:given_name=>"Tim", :family_name=>"Berners-Lee"}] ,
|
92
|
+
:child_index => :first,
|
93
|
+
:template => [:person, :affiliation],
|
94
|
+
:values => ["my new value", "another new value"]
|
95
|
+
).to_xml.should == expected_result
|
96
|
+
|
97
|
+
@sample.lookup(:person, {:given_name=>"Tim", :family_name=>"Berners-Lee"}).first.to_xml.should == expected_result
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should accept symbols as arguments for generators/lookups" do
|
101
|
+
# this appends a role of "my role" into the third "person" node in the document
|
102
|
+
expected_result = "<ns3:name type=\"personal\">\n <ns3:namePart type=\"family\">Klimt</ns3:namePart>\n <ns3:namePart type=\"given\">Gustav</ns3:namePart>\n <ns3:role>\n <ns3:roleTerm type=\"text\" authority=\"marcrelator\">creator</ns3:roleTerm>\n <ns3:roleTerm type=\"code\" authority=\"marcrelator\">cre</ns3:roleTerm>\n </ns3:role>\n <ns3:role>\n <ns3:roleTerm type=\"text\" authority=\"marcrelator\">visionary</ns3:roleTerm>\n <ns3:roleTerm type=\"code\" authority=\"marcrelator\">vry</ns3:roleTerm>\n </ns3:role>\n <ns3:role type=\"text\"><ns3:roleTerm>my role</ns3:roleTerm></ns3:role></ns3:name>"
|
103
|
+
|
104
|
+
@sample.property_values_append(
|
105
|
+
:parent_select => :person ,
|
106
|
+
:child_index => 3,
|
107
|
+
:template => :role,
|
108
|
+
:values => "my role"
|
109
|
+
).to_xml.should == expected_result
|
110
|
+
|
111
|
+
@sample.lookup(:person)[3].to_xml.should == expected_result
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should accept parent_select as an (xpath) string and template as a (template) string" do
|
115
|
+
# this uses the provided template to add a node into the first node resulting from the xpath '//oxns:name[@type="personal"]'
|
116
|
+
expected_result = "<ns3:name type=\"personal\">\n <ns3:namePart type=\"family\">Berners-Lee</ns3:namePart>\n <ns3:namePart type=\"given\">Tim</ns3:namePart>\n <ns3:role>\n <ns3:roleTerm type=\"text\" authority=\"marcrelator\">creator</ns3:roleTerm>\n <ns3:roleTerm type=\"code\" authority=\"marcrelator\">cre</ns3:roleTerm>\n </ns3:role>\n <ns3:role type=\"code\" authority=\"marcrelator\"><ns3:roleTerm>creator</ns3:roleTerm></ns3:role></ns3:name>"
|
117
|
+
|
118
|
+
@sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=1]/oxns:role', @sample.ox_namespaces).length.should == 1
|
119
|
+
|
120
|
+
@sample.property_values_append(
|
121
|
+
:parent_select =>'//oxns:name[@type="personal"]',
|
122
|
+
:child_index => 0,
|
123
|
+
:template => 'xml.role { xml.roleTerm( \'#{builder_new_value}\', :type=>\'code\', :authority=>\'marcrelator\') }',
|
124
|
+
:values => "founder"
|
125
|
+
)
|
126
|
+
|
127
|
+
@sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=1]/oxns:role', @sample.ox_namespaces).length.should == 2
|
128
|
+
@sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=1]/oxns:role[last()]/oxns:roleTerm', @sample.ox_namespaces).first.text.should == "founder"
|
129
|
+
|
130
|
+
# @sample.lookup(:person).first.to_xml.should == expected_result
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should support more complex mixing & matching" do
|
134
|
+
expected_result = "<ns3:name type=\"personal\">\n <ns3:namePart type=\"family\">Jobs</ns3:namePart>\n <ns3:namePart type=\"given\">Steve</ns3:namePart>\n <ns3:namePart type=\"date\">2004</ns3:namePart>\n <ns3:role>\n <ns3:roleTerm type=\"text\" authority=\"marcrelator\">creator</ns3:roleTerm>\n <ns3:roleTerm type=\"code\" authority=\"marcrelator\">cre</ns3:roleTerm>\n </ns3:role>\n <ns3:role type=\"code\" authority=\"marcrelator\"><ns3:roleTerm>foo</ns3:roleTerm></ns3:role></ns3:name>"
|
135
|
+
|
136
|
+
@sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=2]/oxns:role', @sample.ox_namespaces).length.should == 1
|
137
|
+
|
138
|
+
@sample.property_values_append(
|
139
|
+
:parent_select =>'//oxns:name[@type="personal"]',
|
140
|
+
:child_index => 1,
|
141
|
+
:template => [ :person, :role, {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}} ],
|
142
|
+
:values => "foo"
|
143
|
+
)
|
144
|
+
|
145
|
+
@sample.ng_xml.xpath('//oxns:name[@type="personal" and position()=2]/oxns:role', @sample.ox_namespaces).length.should == 2
|
146
|
+
@sample.lookup(:person)[1].search("./oxns:role[last()]/oxns:roleTerm", @sample.ox_namespaces).first.text.should == "foo"
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should raise exception if no node corresponds to the provided :parent_select and :child_index"
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
describe ".property_value_update" do
|
154
|
+
|
155
|
+
it "should accept an xpath as :parent_select" do
|
156
|
+
sample_xpath = '//oxns:name[@type="personal"]/oxns:role/oxns:roleTerm[@type="text"]'
|
157
|
+
@sample.property_value_update(
|
158
|
+
:parent_select =>sample_xpath,
|
159
|
+
:child_index => 1,
|
160
|
+
:value => "donor"
|
161
|
+
)
|
162
|
+
@sample.ng_xml.xpath(sample_xpath, @sample.ox_namespaces)[1].text.should == "donor"
|
163
|
+
end
|
164
|
+
|
165
|
+
it "if :select is provided, should update the first node provided by that xpath statement" do
|
166
|
+
sample_xpath = '//oxns:name[@type="personal" and position()=1]/oxns:namePart[@type="given"]'
|
167
|
+
@sample.property_value_update(
|
168
|
+
:select =>sample_xpath,
|
169
|
+
:value => "Timmeh"
|
170
|
+
)
|
171
|
+
@sample.ng_xml.xpath(sample_xpath, @sample.ox_namespaces).first.text.should == "Timmeh"
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should replace the existing node if you pass a template and values" do
|
175
|
+
pending
|
176
|
+
@sample.property_value_update(
|
177
|
+
:parent_select =>'//oxns:name[@type="personal"]',
|
178
|
+
:child_index => 1,
|
179
|
+
:template => [ :person, :role, {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}} ],
|
180
|
+
:value => "foo"
|
181
|
+
)
|
182
|
+
1.should == 2
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe ".property_value_delete" do
|
187
|
+
it "should accept an xpath query as :select option" do
|
188
|
+
generic_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role'
|
189
|
+
specific_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role[oxns:roleTerm="visionary"]'
|
190
|
+
select_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role[last()]'
|
191
|
+
|
192
|
+
# Check that we're starting with 2 roles
|
193
|
+
# Check that the specific node we want to delete exists
|
194
|
+
@sample.lookup(generic_xpath).length.should == 2
|
195
|
+
@sample.lookup(specific_xpath).length.should == 1
|
196
|
+
|
197
|
+
@sample.property_value_delete(
|
198
|
+
:select =>select_xpath
|
199
|
+
)
|
200
|
+
# Check that we're finishing with 1 role
|
201
|
+
@sample.lookup(generic_xpath).length.should == 1
|
202
|
+
# Check that the specific node we want to delete no longer exists
|
203
|
+
@sample.lookup(specific_xpath).length.should == 0
|
204
|
+
end
|
205
|
+
it "should accept :parent_select, :parent_index and :child_index options instead of a :select" do
|
206
|
+
|
207
|
+
generic_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role/oxns:roleTerm'
|
208
|
+
specific_xpath = '//oxns:name[@type="personal" and position()=4]/oxns:role[oxns:roleTerm="visionary"]'
|
209
|
+
|
210
|
+
# Check that we're starting with 2 roles
|
211
|
+
# Check that the specific node we want to delete exists
|
212
|
+
@sample.lookup(generic_xpath).length.should == 4
|
213
|
+
@sample.lookup(specific_xpath).length.should == 1
|
214
|
+
|
215
|
+
# this is attempting to delete the last child (in this case roleTerm) from the 3rd role in the document.
|
216
|
+
@sample.property_value_delete(
|
217
|
+
:parent_select => [:person, :role],
|
218
|
+
:parent_index => 3,
|
219
|
+
:child_index => :last
|
220
|
+
)
|
221
|
+
|
222
|
+
# Check that we're finishing with 1 role
|
223
|
+
@sample.lookup(generic_xpath).length.should == 3
|
224
|
+
# Check that the specific node we want to delete no longer exists
|
225
|
+
@sample.lookup(specific_xpath).length.should == 1
|
226
|
+
end
|
227
|
+
it "should work if only :parent_select and :child_index are provided" do
|
228
|
+
generic_xpath = '//oxns:name[@type="personal"]/oxns:role'
|
229
|
+
# specific_xpath = '//oxns:name[@type="personal"]/oxns:role'
|
230
|
+
|
231
|
+
# Check that we're starting with 2 roles
|
232
|
+
# Check that the specific node we want to delete exists
|
233
|
+
@sample.lookup(generic_xpath).length.should == 4
|
234
|
+
# @sample.lookup(specific_xpath).length.should == 1
|
235
|
+
|
236
|
+
@sample.property_value_delete(
|
237
|
+
:parent_select => [:person, :role],
|
238
|
+
:child_index => 3
|
239
|
+
)
|
240
|
+
# Check that we're finishing with 1 role
|
241
|
+
@sample.lookup(generic_xpath).length.should == 3
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
require "nokogiri"
|
3
|
+
require "om"
|
4
|
+
|
5
|
+
describe "OM::XML::Validation" do
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
class ValidationTest
|
9
|
+
include OM::XML::Container
|
10
|
+
include OM::XML::Validation
|
11
|
+
self.schema_url = "http://www.loc.gov/standards/mods/v3/mods-3-2.xsd"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
before(:each) do
|
16
|
+
@sample = ValidationTest.from_xml("<foo><bar>1</bar></foo>")
|
17
|
+
end
|
18
|
+
|
19
|
+
## Validation Support
|
20
|
+
# Some of these tests fail when you don't have an internet connection because the mods schema includes other xsd schemas by URL reference.
|
21
|
+
|
22
|
+
describe '#schema_url' do
|
23
|
+
it "should allow you to set the schema url" do
|
24
|
+
ValidationTest.schema_url.should == "http://www.loc.gov/standards/mods/v3/mods-3-2.xsd"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#schema" do
|
29
|
+
it "should return an instance of Nokogiri::XML::Schema loaded from the schema url -- fails if no internet connection" do
|
30
|
+
ValidationTest.schema.should be_kind_of Nokogiri::XML::Schema
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#validate" do
|
35
|
+
it "should validate the provided document against the schema provided in class definition -- fails if no internet connection" do
|
36
|
+
ValidationTest.schema.expects(:validate).with(@sample).returns([])
|
37
|
+
ValidationTest.validate(@sample)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe ".validate" do
|
42
|
+
it "should rely on class validate method" do
|
43
|
+
ValidationTest.expects(:validate).with(@sample)
|
44
|
+
@sample.validate
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#schema_file" do
|
49
|
+
before(:all) do
|
50
|
+
ValidationTest.schema_file = nil
|
51
|
+
end
|
52
|
+
|
53
|
+
after(:all) do
|
54
|
+
ValidationTest.schema_file = fixture("mods-3-2.xsd")
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should lazy load the schema file from the @schema_url" do
|
58
|
+
ValidationTest.instance_variable_get(:@schema_file).should be_nil
|
59
|
+
ValidationTest.expects(:file_from_url).with(ValidationTest.schema_url).returns("fake file").once
|
60
|
+
ValidationTest.schema_file
|
61
|
+
ValidationTest.instance_variable_get(:@schema_file).should == "fake file"
|
62
|
+
ValidationTest.schema_file.should == "fake file"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#file_from_url" do
|
67
|
+
it "should retrieve a file from the provided url over HTTP" do
|
68
|
+
ValidationTest.send(:file_from_url, "http://google.com")
|
69
|
+
end
|
70
|
+
it "should raise an error if the url is invalid" do
|
71
|
+
lambda {ValidationTest.send(:file_from_url, "")}.should raise_error(RuntimeError, "Could not retrieve file from . Error: No such file or directory - ")
|
72
|
+
lambda {ValidationTest.send(:file_from_url, "foo")}.should raise_error(RuntimeError, "Could not retrieve file from foo. Error: No such file or directory - foo")
|
73
|
+
end
|
74
|
+
it "should raise an error if file retrieval fails" do
|
75
|
+
lambda {ValidationTest.send(:file_from_url, "http://fedora-commons.org/nonexistent_file")}.should raise_error(RuntimeError, "Could not retrieve file from http://fedora-commons.org/nonexistent_file. Error: 404 Not Found")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|