opinionated-xml 0.0.1 → 0.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.
- 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
|