mods 2.4.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/ruby.yml +24 -0
- data/.gitignore +1 -0
- data/Gemfile +0 -4
- data/README.md +1 -3
- data/lib/mods/date.rb +51 -17
- data/lib/mods/marc_country_codes.rb +12 -10
- data/lib/mods/nom_terminology.rb +110 -849
- data/lib/mods/reader.rb +9 -39
- data/lib/mods/record.rb +13 -28
- data/lib/mods/version.rb +1 -1
- data/mods.gemspec +3 -3
- data/spec/fixture_data/hp566jq8781.xml +334 -0
- data/spec/integration/parker_spec.rb +217 -0
- data/spec/{date_spec.rb → lib/date_spec.rb} +8 -1
- data/spec/lib/language_spec.rb +123 -0
- data/spec/lib/location_spec.rb +175 -0
- data/spec/lib/name_spec.rb +368 -0
- data/spec/lib/origin_info_spec.rb +134 -0
- data/spec/lib/part_spec.rb +162 -0
- data/spec/lib/physical_description_spec.rb +72 -0
- data/spec/{reader_spec.rb → lib/reader_spec.rb} +1 -41
- data/spec/lib/record_info_spec.rb +114 -0
- data/spec/lib/record_spec.rb +287 -0
- data/spec/lib/related_item_spec.rb +124 -0
- data/spec/lib/subject_spec.rb +427 -0
- data/spec/lib/title_spec.rb +108 -0
- data/spec/lib/top_level_elmnts_simple_spec.rb +169 -0
- data/spec/spec_helper.rb +87 -6
- data/spec/support/fixtures.rb +9 -0
- metadata +61 -43
- data/.coveralls.yml +0 -1
- data/.travis.yml +0 -6
- data/spec/language_spec.rb +0 -118
- data/spec/location_spec.rb +0 -295
- data/spec/name_spec.rb +0 -759
- data/spec/origin_info_spec.rb +0 -447
- data/spec/part_spec.rb +0 -471
- data/spec/physical_description_spec.rb +0 -144
- data/spec/record_info_spec.rb +0 -493
- data/spec/record_spec.rb +0 -356
- data/spec/related_item_spec.rb +0 -305
- data/spec/subject_spec.rb +0 -809
- data/spec/title_spec.rb +0 -226
- data/spec/top_level_elmnts_simple_spec.rb +0 -369
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Mods <physicalDescription> Element" do
|
4
|
+
it "extent child element" do
|
5
|
+
record = mods_record("<physicalDescription><extent>extent</extent></physicalDescription>")
|
6
|
+
expect(record.physical_description.extent.map(&:text)).to eq(["extent"])
|
7
|
+
end
|
8
|
+
|
9
|
+
context "note child element" do
|
10
|
+
subject(:note) do
|
11
|
+
mods_record(<<-XML).physical_description.note
|
12
|
+
<physicalDescription>
|
13
|
+
<form authority='aat'>Graphics</form>
|
14
|
+
<form>plain form</form>
|
15
|
+
<note displayLabel='Dimensions'>dimension text</note>
|
16
|
+
<note displayLabel='Condition'>condition text</note>
|
17
|
+
</physicalDescription>
|
18
|
+
XML
|
19
|
+
end
|
20
|
+
it "should understand note element" do
|
21
|
+
expect(note.map(&:text)).to eq(["dimension text", "condition text"])
|
22
|
+
end
|
23
|
+
it "should understand displayLabel attribute on note element" do
|
24
|
+
expect(note.displayLabel).to eq(["Dimensions", "Condition"])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "form child element" do
|
29
|
+
subject(:physical_description) do
|
30
|
+
mods_record(<<-XML).physical_description
|
31
|
+
<physicalDescription>
|
32
|
+
<form authority='smd'>map</form>
|
33
|
+
<form type='material'>foo</form>
|
34
|
+
<extent>1 map ; 22 x 18 cm.</extent>
|
35
|
+
</physicalDescription>
|
36
|
+
XML
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should understand form element" do
|
40
|
+
expect(physical_description.form.map(&:text)).to eq(["map", "foo"])
|
41
|
+
end
|
42
|
+
it "should understand authority attribute on form element" do
|
43
|
+
expect(physical_description.form.authority).to eq(["smd"])
|
44
|
+
end
|
45
|
+
it "should understand type attribute on form element" do
|
46
|
+
expect(physical_description.form.type_at).to eq(["material"])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "digital materials" do
|
51
|
+
subject(:physical_description) do
|
52
|
+
mods_record(<<-XML).physical_description
|
53
|
+
<physicalDescription>
|
54
|
+
<reformattingQuality>preservation</reformattingQuality>
|
55
|
+
<internetMediaType>image/jp2</internetMediaType>
|
56
|
+
<digitalOrigin>reformatted digital</digitalOrigin>
|
57
|
+
</physicalDescription>
|
58
|
+
XML
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should understand reformattingQuality child element" do
|
62
|
+
expect(physical_description.reformattingQuality.map(&:text)).to eq(["preservation"])
|
63
|
+
end
|
64
|
+
it "should understand digitalOrigin child element" do
|
65
|
+
expect(physical_description.digitalOrigin.map(&:text)).to eq(["reformatted digital"])
|
66
|
+
end
|
67
|
+
it "should understand internetMediaType child element" do
|
68
|
+
expect(physical_description.internetMediaType.map(&:text)).to eq(["image/jp2"])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
@@ -33,7 +33,7 @@ describe "Mods::Reader" do
|
|
33
33
|
|
34
34
|
context "from_file" do
|
35
35
|
before(:all) do
|
36
|
-
@fixture_dir = File.join(File.dirname(__FILE__), 'fixture_data')
|
36
|
+
@fixture_dir = File.join(File.dirname(__FILE__), '../fixture_data')
|
37
37
|
@fixture_mods_file = File.join(@fixture_dir, 'shpc1.mods.xml')
|
38
38
|
@from_file = Mods::Reader.new.from_file(@fixture_mods_file)
|
39
39
|
end
|
@@ -48,7 +48,6 @@ describe "Mods::Reader" do
|
|
48
48
|
context "namespace awareness" do
|
49
49
|
it "should care about namespace by default" do
|
50
50
|
r = Mods::Reader.new
|
51
|
-
expect(r.namespace_aware).to be_truthy
|
52
51
|
expect(@doc_from_str_default_ns.root.namespace.href).to eq(Mods::MODS_NS)
|
53
52
|
expect(@doc_from_str_default_ns.xpath('/m:mods/m:note', @ns_hash).text).to eq("ns")
|
54
53
|
expect(@doc_from_str_default_ns.xpath('/mods/note').size).to eq(0)
|
@@ -61,24 +60,6 @@ describe "Mods::Reader" do
|
|
61
60
|
expect(@doc_from_str_wrong_ns.xpath('/m:mods/m:note', @ns_hash).size).to eq(0)
|
62
61
|
expect(@doc_from_str_wrong_ns.xpath('/mods/note').size).to eq(0)
|
63
62
|
end
|
64
|
-
|
65
|
-
it "should be allowed not to care about namespaces" do
|
66
|
-
r = Mods::Reader.new(false)
|
67
|
-
expect(r.namespace_aware).to be_falsey
|
68
|
-
my_from_str_ns = r.from_str(@example_ns_str)
|
69
|
-
expect(my_from_str_ns.xpath('/m:mods/m:note', @ns_hash).size).to eq(0)
|
70
|
-
expect(my_from_str_ns.xpath('/mods/note').text).to eq("ns")
|
71
|
-
my_from_str_no_ns = r.from_str(@example_no_ns_str)
|
72
|
-
expect(my_from_str_no_ns.xpath('/m:mods/m:note', @ns_hash).size).to eq(0)
|
73
|
-
expect(my_from_str_no_ns.xpath('/mods/note').text).to eq("no ns")
|
74
|
-
my_from_str_wrong_ns = r.from_str(@example_wrong_ns_str)
|
75
|
-
expect(my_from_str_wrong_ns.xpath('/m:mods/m:note', @ns_hash).size).to eq(0)
|
76
|
-
expect(my_from_str_wrong_ns.xpath('/mods/note').text).to eq("wrong ns")
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
it "should do something useful when it gets unparseable XML" do
|
81
|
-
skip "need to implement error handling for bad xml"
|
82
63
|
end
|
83
64
|
|
84
65
|
context "normalizing mods" do
|
@@ -94,19 +75,6 @@ describe "Mods::Reader" do
|
|
94
75
|
reader = Mods::Reader.new.from_str(utf_mods)
|
95
76
|
expect(reader.encoding).to eql("UTF-8")
|
96
77
|
end
|
97
|
-
it "should remove xsi:schemaLocation attribute from mods element if removing namespaces" do
|
98
|
-
str = '<ns3:mods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="http://www.loc.gov/mods/v3" xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-2.xsd">
|
99
|
-
<ns3:note>be very frightened</ns3:note></ns3:mods>'
|
100
|
-
ng_xml = Nokogiri::XML(str)
|
101
|
-
# Nokogiri treats namespaced attributes differently in jruby than in ruby
|
102
|
-
expect(ng_xml.root.has_attribute?('schemaLocation') || ng_xml.root.has_attribute?('xsi:schemaLocation')).to be_truthy
|
103
|
-
r = Mods::Reader.new
|
104
|
-
r.namespace_aware = false
|
105
|
-
r.from_nk_node(ng_xml)
|
106
|
-
# the below are different depending on jruby or ruby ... oy
|
107
|
-
expect(r.mods_ng_xml.root.attributes.keys).not_to include('schemaLocation')
|
108
|
-
expect(r.mods_ng_xml.root.attributes.keys).not_to include('xsi:schemaLocation')
|
109
|
-
end
|
110
78
|
end
|
111
79
|
|
112
80
|
context "from_nk_node" do
|
@@ -142,14 +110,6 @@ describe "Mods::Reader" do
|
|
142
110
|
it "should care about namespace by default" do
|
143
111
|
expect(@mods_ng_doc.xpath('/m:mods/m:titleInfo/m:title', @ns_hash).text).to eq("boo")
|
144
112
|
end
|
145
|
-
it "should be able not to care about namespaces" do
|
146
|
-
@r.namespace_aware = false
|
147
|
-
mods_ng_doc = @r.from_nk_node(@mods_node)
|
148
|
-
expect(mods_ng_doc).to be_kind_of(Nokogiri::XML::Document)
|
149
|
-
expect(mods_ng_doc.xpath('/m:mods/m:titleInfo/m:title', @ns_hash).size).to eq(0)
|
150
|
-
expect(mods_ng_doc.xpath('/mods/titleInfo/title').text).to eq("boo")
|
151
|
-
@r.namespace_aware = true
|
152
|
-
end
|
153
113
|
end # context from_nk_node
|
154
114
|
|
155
115
|
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe "Mods <recordInfo> Element" do
|
4
|
+
context 'with some basic record info' do
|
5
|
+
subject(:record_info) do
|
6
|
+
mods_record("<recordInfo>
|
7
|
+
<recordContentSource authority='marcorg'>RQE</recordContentSource>
|
8
|
+
<recordCreationDate encoding='marc'>890517</recordCreationDate>
|
9
|
+
<recordIdentifier source='SIRSI'>a9079953</recordIdentifier>
|
10
|
+
</recordInfo>").record_info
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'has the expected attributes' do
|
14
|
+
expect(record_info.first).to have_attributes(
|
15
|
+
recordContentSource: match_array(have_attributes(
|
16
|
+
authority: 'marcorg',
|
17
|
+
text: 'RQE'
|
18
|
+
)),
|
19
|
+
recordCreationDate: match_array(have_attributes(
|
20
|
+
encoding: 'marc',
|
21
|
+
text: '890517'
|
22
|
+
)),
|
23
|
+
recordIdentifier: match_array(have_attributes(
|
24
|
+
source: 'SIRSI',
|
25
|
+
text: 'a9079953'
|
26
|
+
))
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with some more expansive record info' do
|
32
|
+
subject(:record_info) do
|
33
|
+
mods_record("<recordInfo>
|
34
|
+
<descriptionStandard>aacr2</descriptionStandard>
|
35
|
+
<recordContentSource authority='marcorg'>AU@</recordContentSource>
|
36
|
+
<recordCreationDate encoding='marc'>050921</recordCreationDate>
|
37
|
+
<recordIdentifier source='SIRSI'>a8837534</recordIdentifier>
|
38
|
+
<languageOfCataloging>
|
39
|
+
<languageTerm authority='iso639-2b' type='code'>eng</languageTerm>
|
40
|
+
</languageOfCataloging>
|
41
|
+
</recordInfo>").record_info
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'has the expected attributes' do
|
45
|
+
expect(record_info.first).to have_attributes(
|
46
|
+
descriptionStandard: match_array(have_attributes(text: 'aacr2')),
|
47
|
+
recordContentSource: match_array(have_attributes(
|
48
|
+
authority: 'marcorg',
|
49
|
+
text: 'AU@'
|
50
|
+
)),
|
51
|
+
recordCreationDate: match_array(have_attributes(
|
52
|
+
encoding: 'marc',
|
53
|
+
text: '050921'
|
54
|
+
)),
|
55
|
+
recordIdentifier: match_array(have_attributes(
|
56
|
+
source: 'SIRSI',
|
57
|
+
text: 'a8837534'
|
58
|
+
)),
|
59
|
+
languageOfCataloging: match_array(have_attributes(
|
60
|
+
languageTerm: match_array(have_attributes(
|
61
|
+
authority: 'iso639-2b',
|
62
|
+
type_at: 'code',
|
63
|
+
text: 'eng'
|
64
|
+
))
|
65
|
+
))
|
66
|
+
)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'with an rlin record info' do
|
71
|
+
subject(:record_info) do
|
72
|
+
mods_record("<recordInfo>
|
73
|
+
<descriptionStandard>appm</descriptionStandard>
|
74
|
+
<recordContentSource authority='marcorg'>CSt</recordContentSource>
|
75
|
+
<recordCreationDate encoding='marc'>850416</recordCreationDate>
|
76
|
+
<recordChangeDate encoding='iso8601'>19991012150824.0</recordChangeDate>
|
77
|
+
<recordIdentifier source='CStRLIN'>a4083219</recordIdentifier>
|
78
|
+
</recordInfo>").record_info
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'has the expected attributes' do
|
82
|
+
expect(record_info.first).to have_attributes(
|
83
|
+
recordChangeDate: match_array(have_attributes(
|
84
|
+
encoding: 'iso8601',
|
85
|
+
text: '19991012150824.0'
|
86
|
+
))
|
87
|
+
)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'with a displayLabel' do
|
92
|
+
subject(:record) do
|
93
|
+
mods_record("<recordInfo displayLabel='val'><recordOrigin>nowhere</recordOrigin></recordInfo></mods>")
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'has the expected attributes' do
|
97
|
+
expect(record.record_info.first).to have_attributes(
|
98
|
+
displayLabel: 'val'
|
99
|
+
)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'with a recordOrigin' do
|
104
|
+
subject(:record) do
|
105
|
+
mods_record("<recordInfo><recordOrigin>human prepared</recordOrigin></recordInfo></mods>")
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'has the expected attributes' do
|
109
|
+
expect(record.record_info.first).to have_attributes(
|
110
|
+
recordOrigin: have_attributes(text: 'human prepared')
|
111
|
+
)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,287 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Mods::Record" do
|
4
|
+
context "from_str" do
|
5
|
+
before(:all) do
|
6
|
+
@mods_ng_doc_w_ns = mods_record('<note>default ns</note>')
|
7
|
+
end
|
8
|
+
it "should return a mods record" do
|
9
|
+
expect(@mods_ng_doc_w_ns).to be_a_kind_of(Mods::Record)
|
10
|
+
end
|
11
|
+
it "should have namespace aware parsing turned on by default" do
|
12
|
+
expect(@mods_ng_doc_w_ns.namespaces.size).to be > 0
|
13
|
+
end
|
14
|
+
it "terminology should work with Record object defaults when mods string has namespaces" do
|
15
|
+
expect(@mods_ng_doc_w_ns.note.map { |e| e.text }).to eq(['default ns'])
|
16
|
+
end
|
17
|
+
it "terminology should not work with Record object defaults when mods string has NO namespaces" do
|
18
|
+
mods_ng_doc = Mods::Record.new.from_str('<mods><note>no ns</note></mods>')
|
19
|
+
expect(mods_ng_doc.note.size).to eq(0)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Be able to create a new Mods::Record from a url
|
24
|
+
context "from_url" do
|
25
|
+
before(:all) do
|
26
|
+
@mods_doc = Mods::Record.new.from_url('http://www.loc.gov/standards/mods/modsrdf/examples/0001.xml')
|
27
|
+
end
|
28
|
+
it "should return a mods record" do
|
29
|
+
expect(@mods_doc).to be_a_kind_of(Mods::Record)
|
30
|
+
end
|
31
|
+
it "should raise an error on a bad url" do
|
32
|
+
expect{Mods::Record.new.from_url("http://example.org/fake.xml")}.to raise_error
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Be able to create a new Mods::Record from a file
|
37
|
+
context "from_file" do
|
38
|
+
before(:all) do
|
39
|
+
@fixture_dir = File.join(File.dirname(__FILE__), '../fixture_data')
|
40
|
+
@mods_doc = Mods::Record.new.from_file(File.join(@fixture_dir, 'shpc1.mods.xml'))
|
41
|
+
end
|
42
|
+
it "should return a mods record" do
|
43
|
+
expect(@mods_doc).to be_a_kind_of(Mods::Record)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "from_nk_node" do
|
48
|
+
before(:all) do
|
49
|
+
oai_resp = '<?xml version="1.0" encoding="UTF-8"?>
|
50
|
+
<OAI-PMH xmlns="http://www.openarchives.org/OAI/2.0/">
|
51
|
+
<responseDate>2012-11-13T22:11:35Z</responseDate>
|
52
|
+
<request>http://sul-lyberservices-prod.stanford.edu/sw-oai-provider/oai</request>
|
53
|
+
<GetRecord>
|
54
|
+
<record>
|
55
|
+
<header>
|
56
|
+
<identifier>oai:searchworks.stanford.edu/druid:mm848sz7984</identifier>
|
57
|
+
<datestamp>2012-10-28T01:06:31Z</datestamp>
|
58
|
+
</header>
|
59
|
+
<metadata>
|
60
|
+
<ns3:mods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="http://www.loc.gov/mods/v3" xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-2.xsd">
|
61
|
+
<ns3:titleInfo>
|
62
|
+
<ns3:title>boo</ns3:title>
|
63
|
+
</ns3:titleInfo>
|
64
|
+
</ns3:mods>
|
65
|
+
</metadata>
|
66
|
+
</record>
|
67
|
+
</GetRecord>
|
68
|
+
</OAI-PMH>'
|
69
|
+
ng_xml = Nokogiri::XML(oai_resp)
|
70
|
+
@mods_node = ng_xml.xpath('//mods:mods', mods: 'http://www.loc.gov/mods/v3').first
|
71
|
+
@mods_ng_doc = Mods::Record.new.from_nk_node(@mods_node)
|
72
|
+
bad_ns_wrapped = '<?xml version="1.0" encoding="UTF-8"?>
|
73
|
+
<metadata>
|
74
|
+
<n:mods xmlns:n="http://www.not.mods.org">
|
75
|
+
<n:titleInfo>
|
76
|
+
<n:title>What? No namespaces?</n:title>
|
77
|
+
</n:titleInfo>
|
78
|
+
</n:mods>
|
79
|
+
</metadata>'
|
80
|
+
ng_xml = Nokogiri::XML(bad_ns_wrapped)
|
81
|
+
@mods_node_no_ns = ng_xml.xpath('//n:mods', {'n'=>'http://www.not.mods.org'}).first
|
82
|
+
end
|
83
|
+
it "should return a mods record" do
|
84
|
+
expect(@mods_ng_doc).to be_a_kind_of(Mods::Record)
|
85
|
+
end
|
86
|
+
it "should have namespace aware parsing turned on by default" do
|
87
|
+
expect(@mods_ng_doc.namespaces.size).to be > 0
|
88
|
+
end
|
89
|
+
it "terminology should work with Record object defaults when mods string has namespaces" do
|
90
|
+
expect(@mods_ng_doc.title_info.title.map { |e| e.text }).to eq(["boo"])
|
91
|
+
end
|
92
|
+
it "terminology should not work with Record object defaults when mods node has NO namespaces" do
|
93
|
+
mods_ng_doc = Mods::Record.new.from_nk_node(@mods_node_no_ns)
|
94
|
+
expect(mods_ng_doc.title_info.title.size).to eq(0)
|
95
|
+
end
|
96
|
+
end # context from_nk_node
|
97
|
+
|
98
|
+
context "getting term values" do
|
99
|
+
subject(:mods_rec) do
|
100
|
+
mods_record(<<-XML)
|
101
|
+
<abstract>single</abstract>
|
102
|
+
<genre></genre>
|
103
|
+
<note>mult1</note>
|
104
|
+
<note>mult2</note>
|
105
|
+
<subject><topic>topic1</topic><topic>topic2</topic></subject>
|
106
|
+
<subject><topic>topic3</topic></subject>
|
107
|
+
XML
|
108
|
+
end
|
109
|
+
|
110
|
+
context "term_value (single value result)" do
|
111
|
+
it "should return nil if there are no such values in the MODS" do
|
112
|
+
expect(mods_rec.term_value(:identifier)).to be_nil
|
113
|
+
end
|
114
|
+
it "should return nil if there are only empty values in the MODS" do
|
115
|
+
expect(mods_rec.term_value(:genre)).to be_nil
|
116
|
+
end
|
117
|
+
it "should return a String for a single value" do
|
118
|
+
expect(mods_rec.term_value(:abstract)).to eq('single')
|
119
|
+
end
|
120
|
+
it "should return a String containing all values, with separator, for multiple values" do
|
121
|
+
expect(mods_rec.term_value(:note)).to eq('mult1 mult2')
|
122
|
+
end
|
123
|
+
it "should work with an Array of messages passed as the argument" do
|
124
|
+
expect(mods_rec.term_value([:subject, 'topic'])).to eq('topic1 topic2 topic3')
|
125
|
+
end
|
126
|
+
it "should take a separator argument" do
|
127
|
+
expect(mods_rec.term_value(:note, ' -|-')).to eq('mult1 -|-mult2')
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "term_values (multiple values)" do
|
132
|
+
it "should return nil if there are no such values in the MODS" do
|
133
|
+
expect(mods_rec.term_values(:identifier)).to be_nil
|
134
|
+
end
|
135
|
+
it "should return nil if there are only empty values in the MODS" do
|
136
|
+
expect(mods_rec.term_values(:genre)).to be_nil
|
137
|
+
end
|
138
|
+
it "should return an array of size one for a single value" do
|
139
|
+
expect(mods_rec.term_values(:abstract)).to eq(['single'])
|
140
|
+
end
|
141
|
+
it "should return an array of values for multiple values" do
|
142
|
+
expect(mods_rec.term_values(:note)).to eq(['mult1', 'mult2'])
|
143
|
+
end
|
144
|
+
it "should work with an Array of messages passed as the argument" do
|
145
|
+
expect(mods_rec.term_values([:subject, 'topic'])).to eq(['topic1', 'topic2', 'topic3'])
|
146
|
+
end
|
147
|
+
it "should work with a String passed as the argument" do
|
148
|
+
expect(mods_rec.term_values('abstract')).to eq(['single'])
|
149
|
+
end
|
150
|
+
it "should raise an error for an unrecognized message symbol" do
|
151
|
+
expect { mods_rec.term_values(:not_there) }.to raise_error(ArgumentError, "term_values called with unknown argument: :not_there")
|
152
|
+
end
|
153
|
+
it "should raise an error if the argument is an Array containing non-symbols" do
|
154
|
+
expect { mods_rec.term_values([:subject, mods_rec.subject]) }.to raise_error(ArgumentError, /term_values called with Array containing unrecognized class:.*NodeSet.*/)
|
155
|
+
end
|
156
|
+
it "should raise an error if the argument isn't a Symbol or an Array" do
|
157
|
+
expect { mods_rec.term_values(mods_rec.subject) }.to raise_error(ArgumentError, /term_values called with unrecognized argument class:.*NodeSet.*/)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end # getting term values
|
161
|
+
|
162
|
+
context "convenience methods for accessing tricky bits of terminology" do
|
163
|
+
context "title methods" do
|
164
|
+
it "short_titles should return an Array of Strings (multiple titles are legal in Mods)" do
|
165
|
+
record = mods_record("<titleInfo><title>Jerk</title><nonSort>The</nonSort></titleInfo><titleInfo><title>Joke</title></titleInfo>")
|
166
|
+
expect(record.short_titles).to eq(["The Jerk", "Joke"])
|
167
|
+
end
|
168
|
+
it "full_titles should return an Array of Strings (multiple titles are legal in Mods)" do
|
169
|
+
record = mods_record("<titleInfo><title>Jerk</title><nonSort>The</nonSort></titleInfo><titleInfo><title>Joke</title></titleInfo>")
|
170
|
+
expect(record.full_titles).to eq(["The Jerk", "Joke"])
|
171
|
+
end
|
172
|
+
it "sort_title should return a String (sortable fields are single valued)" do
|
173
|
+
record = mods_record("<titleInfo><title>Jerk</title><subTitle>A Tale of Tourettes</subTitle><nonSort>The</nonSort></titleInfo>")
|
174
|
+
expect(record.sort_title).to eq("Jerk A Tale of Tourettes")
|
175
|
+
end
|
176
|
+
it "alternative_titles should return an Array of Strings (multiple alternative titles when there are multiple titleInfo elements)" do
|
177
|
+
record = mods_record("<titleInfo type='alternative'><title>1</title></titleInfo><titleInfo type='alternative'><title>2</title></titleInfo>")
|
178
|
+
expect(record.alternative_titles).to eq(['1', '2'])
|
179
|
+
record = mods_record("<titleInfo type='alternative'><title>1</title><title>2</title></titleInfo>")
|
180
|
+
expect(record.alternative_titles).to eq(['12'])
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
context "personal_names" do
|
185
|
+
before(:all) do
|
186
|
+
@pers_name = 'Crusty'
|
187
|
+
@pers_role = 'creator'
|
188
|
+
@given_family = mods_record('<name type="personal"><namePart type="given">Jorge Luis</namePart><namePart type="family">Borges</namePart></name>')
|
189
|
+
@given_family_date = mods_record('<name type="personal"><namePart type="given">Zaphod</namePart>
|
190
|
+
<namePart type="family">Beeblebrox</namePart>
|
191
|
+
<namePart type="date">1912-2362</namePart></name>')
|
192
|
+
@all_name_parts = mods_record('<name type="personal"><namePart type="given">Given</namePart>
|
193
|
+
<namePart type="family">Family</namePart>
|
194
|
+
<namePart type="termsOfAddress">Mr.</namePart>
|
195
|
+
<namePart type="date">date</namePart></name>')
|
196
|
+
@family_only = mods_record('<name type="personal"><namePart type="family">Family</namePart></name>')
|
197
|
+
@given_only = mods_record('<name type="personal"><namePart type="given">Given</namePart></name>')
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should return an Array of Strings" do
|
201
|
+
record = mods_record("<name type='personal'><namePart>#{@pers_name}</namePart></name>")
|
202
|
+
expect(record.personal_names).to eq([@pers_name])
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should not include the role text" do
|
206
|
+
record = mods_record("<name type='personal'><namePart>#{@pers_name}</namePart></name>")
|
207
|
+
expect(record.personal_names.first).not_to match(@pers_role)
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should prefer displayForm over namePart pieces" do
|
211
|
+
display_form_and_name_parts = mods_record('<name type="personal"><namePart type="given">Jorge Luis</namePart>
|
212
|
+
<namePart type="family">Borges</namePart>
|
213
|
+
<displayForm>display form</displayForm></name>')
|
214
|
+
expect(display_form_and_name_parts.personal_names).to include("display form")
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should put the family namePart first" do
|
218
|
+
expect(@given_family.personal_names.first).to match(/^Borges/)
|
219
|
+
expect(@given_family_date.personal_names.first).to match(/^Beeblebrox/)
|
220
|
+
end
|
221
|
+
it "should not include date" do
|
222
|
+
expect(@given_family_date.personal_names.first).not_to match(/19/)
|
223
|
+
expect(@all_name_parts.personal_names.first).not_to match('date')
|
224
|
+
end
|
225
|
+
it "should include a comma when there is both a family and a given name" do
|
226
|
+
expect(@all_name_parts.personal_names).to include("Family, Given Mr.")
|
227
|
+
end
|
228
|
+
it "should include multiple words in a namePart" do
|
229
|
+
expect(@given_family.personal_names).to include("Borges, Jorge Luis")
|
230
|
+
end
|
231
|
+
it "should not include a comma when there is only a family or given name" do
|
232
|
+
expect(@family_only.personal_names.first).not_to match(/,/)
|
233
|
+
expect(@given_only.personal_names.first).not_to match(/,/)
|
234
|
+
end
|
235
|
+
it "should include terms of address" do
|
236
|
+
expect(@all_name_parts.personal_names.first).to match(/Mr./)
|
237
|
+
end
|
238
|
+
end # personal_names
|
239
|
+
|
240
|
+
context "personal_names_w_dates" do
|
241
|
+
before(:all) do
|
242
|
+
@given_family = mods_record('<name type="personal"><namePart type="given">Jorge Luis</namePart>
|
243
|
+
<namePart type="family">Borges</namePart></name>')
|
244
|
+
@given_family_date = mods_record('<name type="personal"><namePart type="given">Zaphod</namePart>
|
245
|
+
<namePart type="family">Beeblebrox</namePart>
|
246
|
+
<namePart type="date">1912-2362</namePart></name>')
|
247
|
+
@all_name_parts = mods_record('<name type="personal"><namePart type="given">Given</namePart>
|
248
|
+
<namePart type="family">Family</namePart>
|
249
|
+
<namePart type="termsOfAddress">Mr.</namePart>
|
250
|
+
<namePart type="date">date</namePart></name>')
|
251
|
+
end
|
252
|
+
it "should return an Array of Strings" do
|
253
|
+
expect(@given_family_date.personal_names_w_dates).to be_an_instance_of(Array)
|
254
|
+
end
|
255
|
+
it "should include the date when it is available" do
|
256
|
+
expect(@given_family_date.personal_names_w_dates.first).to match(/, 1912-2362$/)
|
257
|
+
expect(@all_name_parts.personal_names_w_dates.first).to match(/, date$/)
|
258
|
+
end
|
259
|
+
it "should be just the personal_name if no date is available" do
|
260
|
+
expect(@given_family.personal_names_w_dates.first).to eq('Borges, Jorge Luis')
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
context "corporate_names" do
|
265
|
+
before(:all) do
|
266
|
+
@corp_name = 'ABC corp'
|
267
|
+
end
|
268
|
+
it "should return an Array of Strings" do
|
269
|
+
record = mods_record("<name type='corporate'><namePart>#{@corp_name}</namePart></name></mods>")
|
270
|
+
expect(record.corporate_names).to eq([@corp_name])
|
271
|
+
end
|
272
|
+
it "should not include the role text" do
|
273
|
+
corp_role = 'lithographer'
|
274
|
+
mods_w_corp_name_role = mods_record("<name type='corporate'><namePart>#{@corp_name}</namePart>
|
275
|
+
<role><roleTerm type='text'>#{corp_role}</roleTerm></role></name>")
|
276
|
+
expect(mods_w_corp_name_role.corporate_names.first).not_to match(corp_role)
|
277
|
+
end
|
278
|
+
|
279
|
+
it "should prefer displayForm over namePart pieces" do
|
280
|
+
display_form_and_name_parts = mods_record("<name type='corporate'><namePart>Food, Inc.</namePart>
|
281
|
+
<displayForm>display form</displayForm></name>")
|
282
|
+
expect(display_form_and_name_parts.corporate_names).to include("display form")
|
283
|
+
end
|
284
|
+
end # corporate_names
|
285
|
+
end # convenience methods for tricky bits of terminology
|
286
|
+
|
287
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Mods <relatedItem> Element" do
|
4
|
+
context 'with a bibliography' do
|
5
|
+
subject(:related_item) do
|
6
|
+
mods_record(<<-XML).related_item.first
|
7
|
+
<relatedItem displayLabel='Bibliography' type='host'>
|
8
|
+
<titleInfo>
|
9
|
+
<title/>
|
10
|
+
</titleInfo>
|
11
|
+
<recordInfo>
|
12
|
+
<recordIdentifier source='Gallica ARK'/>
|
13
|
+
</recordInfo>
|
14
|
+
<typeOfResource>text</typeOfResource>
|
15
|
+
</relatedItem>
|
16
|
+
XML
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'has the expected attributes' do
|
20
|
+
expect(related_item).to have_attributes(
|
21
|
+
displayLabel: 'Bibliography',
|
22
|
+
type_at: 'host',
|
23
|
+
recordInfo: match_array([
|
24
|
+
have_attributes(recordIdentifier: match_array([have_attributes(source: 'Gallica ARK')]))
|
25
|
+
]),
|
26
|
+
typeOfResource: match_array([have_attributes(text: 'text')])
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with a related item' do
|
32
|
+
subject(:related_items) do
|
33
|
+
mods_record(<<-XML).related_item
|
34
|
+
<relatedItem>
|
35
|
+
<titleInfo>
|
36
|
+
<title>Complete atlas, or, Distinct view of the known world</title>
|
37
|
+
</titleInfo>
|
38
|
+
<name type='personal'>
|
39
|
+
<namePart>Bowen, Emanuel,</namePart>
|
40
|
+
<namePart type='date'>d. 1767</namePart>
|
41
|
+
</name>
|
42
|
+
</relatedItem>
|
43
|
+
<relatedItem type='host' displayLabel='From:'>
|
44
|
+
<titleInfo>
|
45
|
+
<title>Complete atlas, or, Distinct view of the known world</title>
|
46
|
+
</titleInfo>
|
47
|
+
<name>
|
48
|
+
<namePart>Bowen, Emanuel, d. 1767.</namePart>
|
49
|
+
</name>
|
50
|
+
<identifier type='local'>(AuCNL)1669726</identifier>
|
51
|
+
</relatedItem>
|
52
|
+
XML
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'has the expected attributes' do
|
56
|
+
expect(related_items).to match_array([
|
57
|
+
have_attributes(
|
58
|
+
displayLabel: [],
|
59
|
+
titleInfo: match_array([have_attributes(title: have_attributes(text: 'Complete atlas, or, Distinct view of the known world'))]),
|
60
|
+
personal_name: match_array([
|
61
|
+
have_attributes(type_at: 'personal', display_value: 'Bowen, Emanuel,', date: match_array(have_attributes(text: 'd. 1767')))
|
62
|
+
])
|
63
|
+
),
|
64
|
+
have_attributes(
|
65
|
+
displayLabel: 'From:',
|
66
|
+
type_at: 'host',
|
67
|
+
identifier: match_array([
|
68
|
+
have_attributes(type_at: 'local', text: '(AuCNL)1669726')
|
69
|
+
])
|
70
|
+
)
|
71
|
+
])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'with a constituent item' do
|
76
|
+
subject(:related_item) do
|
77
|
+
mods_record(<<-XML).related_item.first
|
78
|
+
<relatedItem type='constituent' ID='MODSMD_ARTICLE1'>
|
79
|
+
<titleInfo>
|
80
|
+
<title>Nuppineula.</title>
|
81
|
+
</titleInfo>
|
82
|
+
<genre>article</genre>
|
83
|
+
<part ID='DIVL15' type='paragraph' order='1'/>
|
84
|
+
<part ID='DIVL17' type='paragraph' order='2'/>
|
85
|
+
<part ID='DIVL19' type='paragraph' order='3'/>
|
86
|
+
</relatedItem>
|
87
|
+
XML
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'has the expected attributes' do
|
91
|
+
expect(related_item).to have_attributes(
|
92
|
+
id_at: 'MODSMD_ARTICLE1',
|
93
|
+
type_at: 'constituent',
|
94
|
+
titleInfo: match_array([have_attributes(title: have_attributes(text: 'Nuppineula.'))]),
|
95
|
+
genre: have_attributes(text: 'article'),
|
96
|
+
part: match_array([
|
97
|
+
have_attributes(id_at: 'DIVL15', type_at: 'paragraph', order: '1'),
|
98
|
+
have_attributes(id_at: 'DIVL17', type_at: 'paragraph', order: '2'),
|
99
|
+
have_attributes(id_at: 'DIVL19', type_at: 'paragraph', order: '3')
|
100
|
+
])
|
101
|
+
)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'with a collection' do
|
106
|
+
subject(:related_item) do
|
107
|
+
mods_record(<<-XML).related_item.first
|
108
|
+
<relatedItem type='host'>
|
109
|
+
<titleInfo>
|
110
|
+
<title>The Collier Collection of the Revs Institute for Automotive Research</title>
|
111
|
+
</titleInfo>
|
112
|
+
<typeOfResource collection='yes'/>
|
113
|
+
</relatedItem>
|
114
|
+
XML
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'has the expected attributes' do
|
118
|
+
expect(related_item).to have_attributes(
|
119
|
+
titleInfo: match_array([have_attributes(title: have_attributes(text: 'The Collier Collection of the Revs Institute for Automotive Research'))]),
|
120
|
+
typeOfResource: match_array([have_attributes(collection: 'yes')])
|
121
|
+
)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|