opinionated-xml 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/History.textile +1 -0
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/lib/opinionated-xml/ox.rb +430 -0
- data/lib/opinionated-xml/ox_property_values_helper.rb +62 -0
- data/lib/opinionated-xml.rb +9 -0
- data/opinionated-xml.gemspec +77 -0
- data/spec/fixtures/CBF_MODS/ARS0025_016.xml +94 -0
- data/spec/fixtures/mods-3-2.xsd +1 -24
- data/spec/fixtures/test_dummy_mods.xml +19 -0
- data/spec/helpers/ox_property_values_helper_spec.rb +55 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/unit/opinionated-xml_spec.rb +300 -0
- data/spec/unit/ox_integration_spec.rb +124 -0
- metadata +147 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{opinionated-xml}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Matt Zumwalt"]
|
12
|
+
s.date = %q{2010-05-16}
|
13
|
+
s.description = %q{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
|
+
s.email = %q{matt.zumwalt@yourmediashelf.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"History.textile",
|
23
|
+
"LICENSE",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"lib/opinionated-xml.rb",
|
28
|
+
"lib/opinionated-xml/ox.rb",
|
29
|
+
"lib/opinionated-xml/ox_property_values_helper.rb",
|
30
|
+
"opinionated-xml.gemspec",
|
31
|
+
"spec/fixtures/CBF_MODS/ARS0025_016.xml",
|
32
|
+
"spec/fixtures/mods-3-2.xsd",
|
33
|
+
"spec/fixtures/test_dummy_mods.xml",
|
34
|
+
"spec/helpers/ox_property_values_helper_spec.rb",
|
35
|
+
"spec/spec.opts",
|
36
|
+
"spec/spec_helper.rb",
|
37
|
+
"spec/unit/opinionated-xml_spec.rb",
|
38
|
+
"spec/unit/ox_integration_spec.rb"
|
39
|
+
]
|
40
|
+
s.homepage = %q{http://github.com/mediashelf/opinionated-xml}
|
41
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
42
|
+
s.require_paths = ["lib"]
|
43
|
+
s.rubygems_version = %q{1.3.6}
|
44
|
+
s.summary = %q{A library to help you tame sprawling XML schemas like MODS.}
|
45
|
+
s.test_files = [
|
46
|
+
"spec/helpers/ox_property_values_helper_spec.rb",
|
47
|
+
"spec/spec_helper.rb",
|
48
|
+
"spec/unit/opinionated-xml_spec.rb",
|
49
|
+
"spec/unit/ox_integration_spec.rb"
|
50
|
+
]
|
51
|
+
|
52
|
+
if s.respond_to? :specification_version then
|
53
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
54
|
+
s.specification_version = 3
|
55
|
+
|
56
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
57
|
+
s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
|
58
|
+
s.add_runtime_dependency(%q<facets>, [">= 0"])
|
59
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
60
|
+
s.add_development_dependency(%q<mocha>, [">= 0.9.8"])
|
61
|
+
s.add_development_dependency(%q<ruby-debug>, [">= 0"])
|
62
|
+
else
|
63
|
+
s.add_dependency(%q<nokogiri>, [">= 0"])
|
64
|
+
s.add_dependency(%q<facets>, [">= 0"])
|
65
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
66
|
+
s.add_dependency(%q<mocha>, [">= 0.9.8"])
|
67
|
+
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
68
|
+
end
|
69
|
+
else
|
70
|
+
s.add_dependency(%q<nokogiri>, [">= 0"])
|
71
|
+
s.add_dependency(%q<facets>, [">= 0"])
|
72
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
73
|
+
s.add_dependency(%q<mocha>, [">= 0.9.8"])
|
74
|
+
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
@@ -0,0 +1,94 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
2
|
+
<ns3:mods xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="http://www.loc.gov/mods/v3" xmlns:ns2="http://www.w3.org/1999/xlink">
|
3
|
+
<ns3:titleInfo>
|
4
|
+
<ns3:title>Brandenburg concerto no. 1 in F major</ns3:title>
|
5
|
+
</ns3:titleInfo>
|
6
|
+
<ns3:language>
|
7
|
+
<ns3:languageTerm type="code" authority="iso639-2b">No_linguistic_content</ns3:languageTerm>
|
8
|
+
<ns3:languageTerm type="text">No linguistic content</ns3:languageTerm>
|
9
|
+
</ns3:language>
|
10
|
+
<ns3:typeOfResource>sound recording-musical</ns3:typeOfResource>
|
11
|
+
<ns3:originInfo>
|
12
|
+
<ns3:dateCreated>07/23/1962</ns3:dateCreated>
|
13
|
+
</ns3:originInfo>
|
14
|
+
<ns3:name type="personal" authority="ingest">
|
15
|
+
<ns3:role>
|
16
|
+
<ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
|
17
|
+
<ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
|
18
|
+
</ns3:role>
|
19
|
+
<ns3:namePart type="family">Bach, Johann Sebastian, 1685-1750</ns3:namePart>
|
20
|
+
<ns3:displayForm>Bach, Johann Sebastian, 1685-1750</ns3:displayForm>
|
21
|
+
</ns3:name>
|
22
|
+
<ns3:name type="personal" authority="ingest">
|
23
|
+
<ns3:role>
|
24
|
+
<ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
|
25
|
+
<ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
|
26
|
+
</ns3:role>
|
27
|
+
<ns3:namePart type="family">Bergstone, Fred</ns3:namePart>
|
28
|
+
<ns3:displayForm>Bergstone, Fred</ns3:displayForm>
|
29
|
+
</ns3:name>
|
30
|
+
<ns3:name type="personal" authority="ingest">
|
31
|
+
<ns3:role>
|
32
|
+
<ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
|
33
|
+
<ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
|
34
|
+
</ns3:role>
|
35
|
+
<ns3:namePart type="family">Dust\u00E9, Raymond</ns3:namePart>
|
36
|
+
<ns3:displayForm>Dust\u00E9, Raymond</ns3:displayForm>
|
37
|
+
</ns3:name>
|
38
|
+
<ns3:name type="personal" authority="ingest">
|
39
|
+
<ns3:role>
|
40
|
+
<ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
|
41
|
+
<ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
|
42
|
+
</ns3:role>
|
43
|
+
<ns3:namePart type="family">Kates, Philip</ns3:namePart>
|
44
|
+
<ns3:displayForm>Kates, Philip</ns3:displayForm>
|
45
|
+
</ns3:name>
|
46
|
+
<ns3:name type="personal" authority="ingest">
|
47
|
+
<ns3:role>
|
48
|
+
<ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
|
49
|
+
<ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
|
50
|
+
</ns3:role>
|
51
|
+
<ns3:namePart type="family">Price, Charles Gower, 1939-</ns3:namePart>
|
52
|
+
<ns3:displayForm>Price, Charles Gower, 1939-</ns3:displayForm>
|
53
|
+
</ns3:name>
|
54
|
+
<ns3:name type="personal" authority="ingest">
|
55
|
+
<ns3:role>
|
56
|
+
<ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
|
57
|
+
<ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
|
58
|
+
</ns3:role>
|
59
|
+
<ns3:namePart type="family">Taylor, Ross, arranger</ns3:namePart>
|
60
|
+
<ns3:displayForm>Taylor, Ross, arranger</ns3:displayForm>
|
61
|
+
</ns3:name>
|
62
|
+
<ns3:name type="personal" authority="ingest">
|
63
|
+
<ns3:role>
|
64
|
+
<ns3:roleTerm type="text" authority="marcrelator">creator</ns3:roleTerm>
|
65
|
+
<ns3:roleTerm type="code" authority="marcrelator">cre</ns3:roleTerm>
|
66
|
+
</ns3:role>
|
67
|
+
<ns3:namePart type="family">Waller, Rosemary</ns3:namePart>
|
68
|
+
<ns3:displayForm>Waller, Rosemary</ns3:displayForm>
|
69
|
+
</ns3:name>
|
70
|
+
<ns3:subject authority="lcsh">
|
71
|
+
<ns3:topic>Concerti grossi</ns3:topic>
|
72
|
+
</ns3:subject>
|
73
|
+
<ns3:note displayLabel="Uniform title">Bach, Johann Sebastian, 1685-1750. Brandenburgische Konzerte. Nr. 1
|
74
|
+
|
75
|
+
</ns3:note>
|
76
|
+
<ns3:physicalDescription>
|
77
|
+
<ns3:note displayLabel="General Physical Description note">1 7 in. open reel audio tape</ns3:note>
|
78
|
+
</ns3:physicalDescription>
|
79
|
+
<ns3:relatedItem type="host">
|
80
|
+
<ns3:titleInfo>
|
81
|
+
<ns3:title>Carmel Bach Festival Tape Collection</ns3:title>
|
82
|
+
</ns3:titleInfo>
|
83
|
+
<ns3:originInfo>
|
84
|
+
<ns3:dateCreated>1962-1982</ns3:dateCreated>
|
85
|
+
<ns3:dateCreated point="start">1962</ns3:dateCreated>
|
86
|
+
<ns3:dateCreated point="end">1982</ns3:dateCreated>
|
87
|
+
</ns3:originInfo>
|
88
|
+
<ns3:identifier type="local">ARS.0025</ns3:identifier>
|
89
|
+
</ns3:relatedItem>
|
90
|
+
<ns3:note displayLabel="Digital object made available by ">Archive of Recorded Sound, Braun Music Center, 541 Lasuen Mall, Stanford University, Stanford, California, 94305-3076, USA, (http://library.stanford.edu/depts/ars)</ns3:note>
|
91
|
+
<ns3:identifier displayLabel="Audio-Streaming">ARS0025_016_a_sl.mp3</ns3:identifier>
|
92
|
+
<ns3:identifier displayLabel="Audio-Service">ARS0025_016_a_sh.wav</ns3:identifier>
|
93
|
+
<ns3:identifier displayLabel="Audio-Master">ARS0025_016_a_pm.wav</ns3:identifier>
|
94
|
+
</ns3:mods>
|
@@ -0,0 +1 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
Tentative plan for 4.0 is to make it an element instead of an attribute,
|
1
3
|
and wrap <url> and <urlNote> together. Can't do that in 3.2
|
2
4
|
because it would not be compatible with 3.1.
|
3
5
|
but had not been explicitly typed, are now typed.
|
4
6
|
http://www.loc.gov/standards/xlink.xsd.
|
5
7
|
(It was previously http://www.loc.gov/standards/mods/xlink.xsd.
|
6
8
|
The schema now resides in both places so that earlier versions
|
7
9
|
will not be affected, but it is now intended that the new copy
|
8
10
|
be referenced, outside of the mods directory,
|
9
11
|
so that other projects, e.g. mets, may reference it.)
|
10
12
|
(1) a single MODS record:
|
11
13
|
record definintion, and also relatedItem.
|
12
14
|
Difference is that mods requires at least one element
|
13
15
|
and relatedItem does not.
|
14
|
-
->
|
15
|
-
->
|
16
16
|
|
17
17
|
********** titleInfoType definition **********
|
18
18
|
-->
|
19
19
|
********** nameType definition **********
|
20
|
-
->
|
21
|
-
->
|
22
|
-
->
|
23
20
|
</xsd:documentation>
|
24
|
-
->
|
25
21
|
-->
|
26
|
-
->
|
27
22
|
********** originInfoType definition **********
|
28
|
-
->
|
29
|
-
->
|
30
|
-
->
|
31
23
|
-->
|
32
24
|
-->
|
33
25
|
-->
|
34
26
|
-->
|
35
27
|
-->
|
36
28
|
********** subjectType definition **********
|
37
|
-
->
|
38
|
-
->
|
39
|
-
->
|
40
|
-
->
|
41
|
-
->
|
42
|
-
->
|
43
29
|
-->
|
44
30
|
|
45
31
|
-->
|
46
32
|
-->
|
47
|
-
->
|
48
|
-
->
|
49
|
-
->
|
50
|
-
->
|
51
|
-
->
|
52
|
-
->
|
53
|
-
->
|
54
33
|
********** language attribute group definition **********
|
55
|
-
->
|
56
34
|
********** definition of codeOrText type used by type attribute
|
57
35
|
for elements that distinguish code from text **********
|
58
36
|
-->
|
59
37
|
********** definition of placeAuthority type used by authority attribute
|
60
38
|
for placeType and geographic **********
|
61
39
|
-->
|
62
40
|
********** definition of nameTypeAttribute used by name attribute
|
63
41
|
"type" **********
|
64
42
|
-->
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
2
|
+
<ns3:mods xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-2.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="http://www.loc.gov/mods/v3" xmlns:ns2="http://www.w3.org/1999/xlink">
|
3
|
+
<ns3:name type="personal">
|
4
|
+
<ns3:namePart type="family">Berners-Lee</ns3:namePart>
|
5
|
+
<ns3:namePart type="given">Tim</ns3:namePart>
|
6
|
+
</ns3:name>
|
7
|
+
<ns3:name type="personal">
|
8
|
+
<ns3:namePart type="family">Jobs</ns3:namePart>
|
9
|
+
<ns3:namePart type="given">Steve</ns3:namePart>
|
10
|
+
</ns3:name>
|
11
|
+
<ns3:name type="personal">
|
12
|
+
<ns3:namePart type="family">Wozniak</ns3:namePart>
|
13
|
+
<ns3:namePart type="given">The Woz</ns3:namePart>
|
14
|
+
</ns3:name>
|
15
|
+
<ns3:name type="personal">
|
16
|
+
<ns3:namePart type="family">Klimt</ns3:namePart>
|
17
|
+
<ns3:namePart type="given">Gustav</ns3:namePart>
|
18
|
+
</ns3:name>
|
19
|
+
</ns3:mods>
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
class FakePVHClass
|
4
|
+
include OX::PropertyValuesHelper
|
5
|
+
end
|
6
|
+
|
7
|
+
def helper
|
8
|
+
@fake_includer
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "OX::PropertyValuesHelper" do
|
12
|
+
|
13
|
+
before(:all) do
|
14
|
+
@fake_includer = FakePVHClass.new
|
15
|
+
end
|
16
|
+
|
17
|
+
describe ".property_values" do
|
18
|
+
|
19
|
+
it "should call .lookup and then build an array of values from the returned nodeset (using default_node, etc as nessesary)" do
|
20
|
+
lookup_opts = "insert args here"
|
21
|
+
mock_node = mock("node")
|
22
|
+
mock_node.expects(:text).returns("sample value").times(3)
|
23
|
+
mock_nodeset = [mock_node, mock_node, mock_node]
|
24
|
+
helper.expects(:lookup).with(lookup_opts).returns(mock_nodeset)
|
25
|
+
|
26
|
+
helper.property_values(lookup_opts).should == ["sample value","sample value","sample value"]
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
describe ".property_values_append" do
|
32
|
+
|
33
|
+
# see ../unit/ox_integration_spec.rb
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
describe ".property_value_set" do
|
38
|
+
|
39
|
+
it "should " do
|
40
|
+
pending "in progress..."
|
41
|
+
@fixturemods.property_value_set('//oxns:name[@type="personal"]',1,"foo")
|
42
|
+
@fixturemods.property_value_set([ [:person,:role], "donor"], 5, "special donor")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "could support alternative notation" do
|
46
|
+
pending "this would be for the sake of consistency with the method signature of property_values_append"
|
47
|
+
# @fixturemods.property_value_set(
|
48
|
+
# :node_select =>'//oxns:name[@type="personal"]',
|
49
|
+
# :node_index => 1,
|
50
|
+
# :values => "foo"
|
51
|
+
# ).to_xml.should == expected_result
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
require 'opinionated-xml'
|
4
|
+
require 'spec'
|
5
|
+
require 'spec/autorun'
|
6
|
+
require 'ruby-debug'
|
7
|
+
|
8
|
+
Spec::Runner.configure do |config|
|
9
|
+
config.mock_with :mocha
|
10
|
+
end
|
11
|
+
|
12
|
+
def fixture(file)
|
13
|
+
File.new(File.join(File.dirname(__FILE__), 'fixtures', file))
|
14
|
+
end
|
@@ -0,0 +1,300 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe "OpinionatedXml" do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
#ModsHelpers.name_("Beethoven, Ludwig van", :date=>"1770-1827", :role=>"creator")
|
7
|
+
class FakeOxMods < Nokogiri::XML::Document
|
8
|
+
|
9
|
+
include OX
|
10
|
+
|
11
|
+
# Could add support for multiple root declarations.
|
12
|
+
# For now, assume that any modsCollections have already been broken up and fed in as individual mods documents
|
13
|
+
# root :mods_collection, :path=>"modsCollection",
|
14
|
+
# :attributes=>[],
|
15
|
+
# :subelements => :mods
|
16
|
+
|
17
|
+
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"
|
18
|
+
|
19
|
+
|
20
|
+
property :name_, :path=>"name",
|
21
|
+
:attributes=>[:xlink, :lang, "xml:lang", :script, :transliteration, {:type=>["personal", "enumerated", "corporate"]} ],
|
22
|
+
:subelements=>["namePart", "displayForm", "affiliation", :role, "description"],
|
23
|
+
:default_content_path => "namePart",
|
24
|
+
:convenience_methods => {
|
25
|
+
:date => {:path=>"namePart", :attributes=>{:type=>"date"}},
|
26
|
+
:family_name => {:path=>"namePart", :attributes=>{:type=>"family"}},
|
27
|
+
:given_name => {:path=>"namePart", :attributes=>{:type=>"given"}},
|
28
|
+
:terms_of_address => {:path=>"namePart", :attributes=>{:type=>"termsOfAddress"}}
|
29
|
+
}
|
30
|
+
|
31
|
+
property :person, :variant_of=>:name_, :attributes=>{:type=>"personal"}
|
32
|
+
|
33
|
+
property :role, :path=>"role",
|
34
|
+
:parents=>[:name_],
|
35
|
+
:attributes=>[ { "type"=>["text", "code"] } , "authority"],
|
36
|
+
:default_content_path => "roleTerm"
|
37
|
+
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
class FakeOtherOx < Nokogiri::XML::Document
|
42
|
+
|
43
|
+
include OX
|
44
|
+
extend OX::ClassMethods
|
45
|
+
|
46
|
+
root_property :other, "other", "http://www.foo.com"
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
before(:each) do
|
53
|
+
@fixturemods = FakeOxMods.parse( fixture( File.join("CBF_MODS", "ARS0025_016.xml") ) )
|
54
|
+
end
|
55
|
+
|
56
|
+
after(:all) do
|
57
|
+
Object.send(:remove_const, :FakeOxMods)
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#new" do
|
61
|
+
it "should set up namespaces" do
|
62
|
+
@fixturemods.ox_namespaces.should == {"oxns"=>"http://www.loc.gov/mods/v3", "xmlns:ns2"=>"http://www.w3.org/1999/xlink", "xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance", "xmlns:ns3"=>"http://www.loc.gov/mods/v3"}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#root_property" do
|
67
|
+
it "should initialize root_property class attributes without attributes bleeding over to other OX classes" do
|
68
|
+
FakeOxMods.root_property_ref.should == :mods
|
69
|
+
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
|
+
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
|
+
FakeOtherOx.root_property_ref.should == :other
|
74
|
+
FakeOtherOx.root_config.should == {:namespace=>"http://www.foo.com", :path=>"other", :ref=>:other}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "#property" do
|
79
|
+
|
80
|
+
it "fails gracefully if you try to look up nodes for an undefined property" do
|
81
|
+
@fixturemods.lookup(:nobody_home).should == []
|
82
|
+
end
|
83
|
+
|
84
|
+
it "constructs xpath queries for finding properties" do
|
85
|
+
FakeOxMods.properties[:name_][:xpath].should == '//oxns:name'
|
86
|
+
FakeOxMods.properties[:name_][:xpath_relative].should == 'oxns:name'
|
87
|
+
|
88
|
+
FakeOxMods.properties[:person][:xpath].should == '//oxns:name[@type="personal"]'
|
89
|
+
FakeOxMods.properties[:person][:xpath_relative].should == 'oxns:name[@type="personal"]'
|
90
|
+
end
|
91
|
+
|
92
|
+
it "constructs templates for value-driven searches" do
|
93
|
+
FakeOxMods.properties[:name_][:xpath_constrained].should == '//oxns:name[contains(oxns:namePart, "#{constraint_value}")]'.gsub('"', '\"')
|
94
|
+
FakeOxMods.properties[:person][:xpath_constrained].should == '//oxns:name[@type="personal" and contains(oxns:namePart, "#{constraint_value}")]'.gsub('"', '\"')
|
95
|
+
|
96
|
+
# Example of how you could use these templates:
|
97
|
+
constraint_value = "SAMPLE CONSTRAINT VALUE"
|
98
|
+
constrained_query = eval( '"' + FakeOxMods.properties[:person][:xpath_constrained] + '"' )
|
99
|
+
constrained_query.should == '//oxns:name[@type="personal" and contains(oxns:namePart, "SAMPLE CONSTRAINT VALUE")]'
|
100
|
+
end
|
101
|
+
|
102
|
+
it "constructs xpath queries & templates for convenience methods" do
|
103
|
+
FakeOxMods.properties[:name_][:convenience_methods][:date][:xpath].should == '//oxns:name/oxns:namePart[@type="date"]'
|
104
|
+
FakeOxMods.properties[:name_][:convenience_methods][:date][:xpath_relative].should == 'oxns:namePart[@type="date"]'
|
105
|
+
FakeOxMods.properties[:name_][:convenience_methods][:date][:xpath_constrained].should == '//oxns:name[contains(oxns:namePart[@type="date"], "#{constraint_value}")]'.gsub('"', '\"')
|
106
|
+
|
107
|
+
FakeOxMods.properties[:person][:convenience_methods][:date][:xpath].should == '//oxns:name[@type="personal"]/oxns:namePart[@type="date"]'
|
108
|
+
FakeOxMods.properties[:person][:convenience_methods][:date][:xpath_relative].should == 'oxns:namePart[@type="date"]'
|
109
|
+
FakeOxMods.properties[:person][:convenience_methods][:date][:xpath_constrained].should == '//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "#{constraint_value}")]'.gsub('"', '\"')
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
it "constructs xpath queries & templates for subelements too" do
|
114
|
+
FakeOxMods.properties[:person][:convenience_methods][:displayForm][:xpath].should == '//oxns:name[@type="personal"]/oxns:displayForm'
|
115
|
+
FakeOxMods.properties[:person][:convenience_methods][:displayForm][:xpath_relative].should == 'oxns:displayForm'
|
116
|
+
FakeOxMods.properties[:person][:convenience_methods][:displayForm][:xpath_constrained].should == '//oxns:name[@type="personal" and contains(oxns:displayForm, "#{constraint_value}")]'.gsub('"', '\"')
|
117
|
+
end
|
118
|
+
|
119
|
+
it "supports subelements that are specified as separate properties" do
|
120
|
+
FakeOxMods.properties[:name_][:convenience_methods][:role][:xpath].should == '//oxns:name/oxns:role'
|
121
|
+
FakeOxMods.properties[:name_][:convenience_methods][:role][:xpath_relative].should == 'oxns:role'
|
122
|
+
FakeOxMods.properties[:name_][:convenience_methods][:role][:xpath_constrained].should == '//oxns:name[contains(oxns:role/oxns:roleTerm, "#{constraint_value}")]'.gsub('"', '\"')
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should not overwrite default property info when adding a variant property" do
|
126
|
+
FakeOxMods.properties[:name_].should_not equal(FakeOxMods.properties[:person])
|
127
|
+
FakeOxMods.properties[:name_][:convenience_methods].should_not equal(FakeOxMods.properties[:person][:convenience_methods])
|
128
|
+
|
129
|
+
FakeOxMods.properties[:name_][:xpath].should_not == FakeOxMods.properties[:person][:xpath]
|
130
|
+
FakeOxMods.properties[:name_][:convenience_methods][:date][:xpath_constrained].should_not == FakeOxMods.properties[:person][:convenience_methods][:date][:xpath_constrained]
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
describe ".lookup" do
|
136
|
+
|
137
|
+
it "uses the generated xpath queries" do
|
138
|
+
@fixturemods.expects(:xpath).with('//oxns:name[@type="personal"]', @fixturemods.ox_namespaces)
|
139
|
+
@fixturemods.lookup(:person)
|
140
|
+
|
141
|
+
@fixturemods.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:namePart, "Beethoven, Ludwig van")]', @fixturemods.ox_namespaces)
|
142
|
+
@fixturemods.lookup(:person, "Beethoven, Ludwig van")
|
143
|
+
|
144
|
+
@fixturemods.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "2010")]', @fixturemods.ox_namespaces)
|
145
|
+
@fixturemods.lookup(:person, :date=>"2010")
|
146
|
+
|
147
|
+
@fixturemods.expects(:xpath).with('//oxns:name[@type="personal" and contains(oxns:role/oxns:roleTerm, "donor")]', @fixturemods.ox_namespaces)
|
148
|
+
@fixturemods.lookup(:person, :role=>"donor")
|
149
|
+
|
150
|
+
# @fixturemods.expects(:xpath).with('//oxns:name[@type="personal"]/oxns:namePart[@type="date"]', @fixturemods.ox_namespaces)
|
151
|
+
# @fixturemods.lookup([:person,:date])
|
152
|
+
|
153
|
+
# @fixturemods.expects(:xpath).with('//oxns:name[contains(oxns:namePart[@type="date"], "2010")]', @fixturemods.ox_namespaces)
|
154
|
+
# @fixturemods.lookup([:person,:date], "2010")
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
describe ".xpath_query_for" do
|
160
|
+
|
161
|
+
it "retrieves the generated xpath query to match your desires" do
|
162
|
+
@fixturemods.xpath_query_for(:person).should == '//oxns:name[@type="personal"]'
|
163
|
+
|
164
|
+
@fixturemods.xpath_query_for(:person, "Beethoven, Ludwig van").should == '//oxns:name[@type="personal" and contains(oxns:namePart, "Beethoven, Ludwig van")]'
|
165
|
+
|
166
|
+
@fixturemods.xpath_query_for(:person, :date=>"2010").should == '//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "2010")]'
|
167
|
+
|
168
|
+
@fixturemods.xpath_query_for(:person, :role=>"donor").should == '//oxns:name[@type="personal" and contains(oxns:role/oxns:roleTerm, "donor")]'
|
169
|
+
|
170
|
+
@fixturemods.xpath_query_for([:person,:date]).should == '//oxns:name[@type="personal"]/oxns:namePart[@type="date"]'
|
171
|
+
|
172
|
+
@fixturemods.xpath_query_for([:person,:date], "2010").should == '//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "2010")]'
|
173
|
+
end
|
174
|
+
|
175
|
+
it "parrots any strings back to you (in case you already have an xpath query)" do
|
176
|
+
@fixturemods.xpath_query_for('//oxns:name[@type="personal"]/oxns:namePart[@type="date"]').should == '//oxns:name[@type="personal"]/oxns:namePart[@type="date"]'
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
describe "#generate_xpath" do
|
182
|
+
it "should generate an xpath query from the options in the provided hash and should support generating xpaths with constraint values" do
|
183
|
+
opts1 = {:path=>"name", :default_content_path=>"namePart"}
|
184
|
+
opts2 = {:path=>"originInfo"}
|
185
|
+
opts3 = {:path=>["name", "namePart"]}
|
186
|
+
FakeOxMods.generate_xpath( opts1 ).should == '//oxns:name'
|
187
|
+
FakeOxMods.generate_xpath( opts1, :constraints=>:default ).should == '//oxns:name[contains(oxns:namePart, "#{constraint_value}")]'
|
188
|
+
FakeOxMods.generate_xpath( opts2, :constraints=>:default ).should == '//oxns:originInfo[contains("#{constraint_value}")]'
|
189
|
+
|
190
|
+
FakeOxMods.generate_xpath( opts1, :variations=>{:attributes=>{:type=>"personal"}} ).should == '//oxns:name[@type="personal"]'
|
191
|
+
FakeOxMods.generate_xpath( opts1, :variations=>{:attributes=>{:type=>"personal"}}, :constraints=>:default ).should == '//oxns:name[@type="personal" and contains(oxns:namePart, "#{constraint_value}")]'
|
192
|
+
|
193
|
+
FakeOxMods.generate_xpath( opts1, :constraints=>{:path=>"namePart", :attributes=>{:type=>"date"}} ).should == '//oxns:name[contains(oxns:namePart[@type="date"], "#{constraint_value}")]'
|
194
|
+
FakeOxMods.generate_xpath( opts1, :constraints=>{:path=>"namePart", :attributes=>{:type=>"date"}}, :variations=>{:attributes=>{:type=>"personal"}} ).should == '//oxns:name[@type="personal" and contains(oxns:namePart[@type="date"], "#{constraint_value}")]'
|
195
|
+
FakeOxMods.generate_xpath(FakeOxMods.properties[:person], :variations=>{:attributes=>{:type=>"personal"}}, :constraints=>{:path=>"role", :default_content_path=>"roleTerm"}, :subelement_of=>":person").should == '//oxns:name[@type="personal" and contains(oxns:role/oxns:roleTerm, "#{constraint_value}")]'
|
196
|
+
|
197
|
+
FakeOxMods.generate_xpath(opts1, :variations=>{:attributes=>{:type=>"personal"}, :subelement_path=>"displayForm" } ).should == '//oxns:name[@type="personal"]/oxns:displayForm'
|
198
|
+
FakeOxMods.generate_xpath(opts1, :variations=>{:attributes=>{:type=>"personal"}}, :constraints=>{:path=>"displayForm"} ).should == '//oxns:name[@type="personal" and contains(oxns:displayForm, "#{constraint_value}")]'
|
199
|
+
FakeOxMods.generate_xpath(opts1, :variations=>{:attributes=>{:type=>"personal"}, :subelement_path=>["role", "roleTerm"] } ).should == '//oxns:name[@type="personal"]/oxns:role/oxns:roleTerm'
|
200
|
+
|
201
|
+
FakeOxMods.generate_xpath( opts3, :variations=>{:attributes=>{:type=>"date"}} ).should == '//oxns:name/oxns:namePart[@type="date"]'
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should support relative paths" do
|
205
|
+
relative_opts = {:path=>"namePart"}
|
206
|
+
FakeOxMods.generate_xpath( relative_opts, :variations=>{:attributes=>{:type=>"date"}}, :relative=>true).should == 'oxns:namePart[@type="date"]'
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should work with real properties hashes" do
|
210
|
+
FakeOxMods.generate_xpath(FakeOxMods.properties[:person], :variations=>FakeOxMods.properties[:person]).should == "//oxns:name[@type=\"personal\"]"
|
211
|
+
FakeOxMods.generate_xpath(FakeOxMods.properties[:person], :variations=>FakeOxMods.properties[:person], :constraints=>{:path=>"role", :default_content_path=>"roleTerm"}, :subelement_of=>":person").should == '//oxns:name[@type="personal" and contains(oxns:role/oxns:roleTerm, "#{constraint_value}")]'
|
212
|
+
date_hash = FakeOxMods.properties[:person][:convenience_methods][:date]
|
213
|
+
FakeOxMods.generate_xpath( date_hash, :variations=>date_hash, :relative=>true ).should == 'oxns:namePart[@type="date"]'
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should support custom templates" do
|
217
|
+
opts = {:path=>"name", :default_content_path=>"namePart"}
|
218
|
+
FakeOxMods.generate_xpath( opts, :template=>'/#{prefix}:sampleNode/#{prefix}:#{path}[contains(#{default_content_path}, \":::constraint_value:::\")]' ).should == '/oxns:sampleNode/oxns:name[contains(namePart, "#{constraint_value}")]'
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe "#builder_template" do
|
223
|
+
|
224
|
+
it "should generate a template call for passing into the builder block (assumes 'xml' as the argument for the block)" do
|
225
|
+
FakeOxMods.builder_template([:person,:date]).should == 'xml.namePart( \'#{builder_new_value}\', :type=>\'date\' )'
|
226
|
+
FakeOxMods.builder_template([:name_,:affiliation]).should == 'xml.affiliation( \'#{builder_new_value}\' )'
|
227
|
+
|
228
|
+
simple_role_builder_template = 'xml.role( :type=>\'text\' ) { xml.roleTerm( \'#{builder_new_value}\' ) }'
|
229
|
+
FakeOxMods.builder_template([:role]).should == simple_role_builder_template
|
230
|
+
FakeOxMods.builder_template([:person,:role]).should == simple_role_builder_template
|
231
|
+
|
232
|
+
marcrelator_role_builder_template = 'xml.role( :type=>\'code\', :authority=>\'marcrelator\' ) { xml.roleTerm( \'#{builder_new_value}\' ) }'
|
233
|
+
FakeOxMods.builder_template([:role], {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}} ).should == marcrelator_role_builder_template
|
234
|
+
FakeOxMods.builder_template([:person,:role], {:attributes=>{"type"=>"code", "authority"=>"marcrelator"}} ).should == marcrelator_role_builder_template
|
235
|
+
end
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
describe "#applicable_attributes" do
|
240
|
+
it "returns a Hash where all of the values are strings" do
|
241
|
+
FakeOxMods.send(:applicable_attributes, {:type=>"date"} ).should == {:type=>"date"}
|
242
|
+
FakeOxMods.send(:applicable_attributes, ["authority", {:type=>["text","code"]}] ).should == {:type=>"text"}
|
243
|
+
end
|
244
|
+
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
|
+
|
300
|
+
end
|