mods 2.4.0 → 3.0.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.
- 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
|