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.
Files changed (45) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ruby.yml +24 -0
  3. data/.gitignore +1 -0
  4. data/Gemfile +0 -4
  5. data/README.md +1 -3
  6. data/lib/mods/date.rb +51 -17
  7. data/lib/mods/marc_country_codes.rb +12 -10
  8. data/lib/mods/nom_terminology.rb +110 -849
  9. data/lib/mods/reader.rb +9 -39
  10. data/lib/mods/record.rb +13 -28
  11. data/lib/mods/version.rb +1 -1
  12. data/mods.gemspec +3 -3
  13. data/spec/fixture_data/hp566jq8781.xml +334 -0
  14. data/spec/integration/parker_spec.rb +217 -0
  15. data/spec/{date_spec.rb → lib/date_spec.rb} +8 -1
  16. data/spec/lib/language_spec.rb +123 -0
  17. data/spec/lib/location_spec.rb +175 -0
  18. data/spec/lib/name_spec.rb +368 -0
  19. data/spec/lib/origin_info_spec.rb +134 -0
  20. data/spec/lib/part_spec.rb +162 -0
  21. data/spec/lib/physical_description_spec.rb +72 -0
  22. data/spec/{reader_spec.rb → lib/reader_spec.rb} +1 -41
  23. data/spec/lib/record_info_spec.rb +114 -0
  24. data/spec/lib/record_spec.rb +287 -0
  25. data/spec/lib/related_item_spec.rb +124 -0
  26. data/spec/lib/subject_spec.rb +427 -0
  27. data/spec/lib/title_spec.rb +108 -0
  28. data/spec/lib/top_level_elmnts_simple_spec.rb +169 -0
  29. data/spec/spec_helper.rb +87 -6
  30. data/spec/support/fixtures.rb +9 -0
  31. metadata +61 -43
  32. data/.coveralls.yml +0 -1
  33. data/.travis.yml +0 -6
  34. data/spec/language_spec.rb +0 -118
  35. data/spec/location_spec.rb +0 -295
  36. data/spec/name_spec.rb +0 -759
  37. data/spec/origin_info_spec.rb +0 -447
  38. data/spec/part_spec.rb +0 -471
  39. data/spec/physical_description_spec.rb +0 -144
  40. data/spec/record_info_spec.rb +0 -493
  41. data/spec/record_spec.rb +0 -356
  42. data/spec/related_item_spec.rb +0 -305
  43. data/spec/subject_spec.rb +0 -809
  44. data/spec/title_spec.rb +0 -226
  45. data/spec/top_level_elmnts_simple_spec.rb +0 -369
@@ -0,0 +1,368 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe "Mods <name> Element" do
4
+ context 'with a record with a provided language' do
5
+ subject(:record) do
6
+ mods_record(<<-XML)
7
+ <name type='personal'><namePart xml:lang='fr-FR' type='given'>Jean</namePart><namePart xml:lang='en-US' type='given'>John</namePart></name>
8
+ XML
9
+ end
10
+
11
+ it "has the expected attributes" do
12
+ expect(record.personal_name.namePart).to match_array([
13
+ have_attributes(text: 'Jean', lang: 'fr-FR', type_at: 'given'),
14
+ have_attributes(text: 'John', lang: 'en-US', type_at: 'given'),
15
+ ])
16
+ end
17
+ end
18
+
19
+ context 'with a recod without a role' do
20
+ subject(:record) do
21
+ mods_record(<<-XML)
22
+ <name type='personal'><namePart>Crusty</namePart></name>
23
+ XML
24
+ end
25
+
26
+ it 'does not have a role' do
27
+ expect(record.personal_name.role).to be_empty
28
+ expect(record.personal_name.role.code).to be_empty
29
+ expect(record.personal_name.role.authority).to be_empty
30
+ end
31
+ end
32
+
33
+ context 'with a record with a text role' do
34
+ subject(:record) do
35
+ mods_record(<<-XML)
36
+ <name type='personal'><namePart>Crusty</namePart>
37
+ <role><roleTerm authority='marcrelator' type='text'>creator</roleTerm><role></name>
38
+ XML
39
+ end
40
+
41
+ it 'has the expected attributes' do
42
+ expect(record.plain_name.first).to have_attributes(
43
+ type_at: 'personal',
44
+ namePart: match_array([
45
+ have_attributes(text: 'Crusty')
46
+ ]),
47
+ role: have_attributes(
48
+ roleTerm: have_attributes(
49
+ text: 'creator',
50
+ type_at: ['text'],
51
+ authority: ['marcrelator']
52
+ ),
53
+ authority: ['marcrelator'],
54
+ code: [],
55
+ value: ['creator']
56
+ )
57
+ )
58
+ end
59
+ end
60
+
61
+ context 'with a record with a code role' do
62
+ subject(:record) do
63
+ mods_record(<<-XML)
64
+ <name type='personal'>
65
+ <namePart type='given'>John</namePart>
66
+ <namePart type='family'>Huston</namePart>
67
+ <role>
68
+ <roleTerm type='code' authority='marcrelator'>drt</roleTerm>
69
+ </role>
70
+ </name>
71
+ XML
72
+ end
73
+
74
+ it 'has the expected attributes' do
75
+ expect(record.plain_name.first).to have_attributes(
76
+ type_at: 'personal',
77
+ display_value: 'Huston, John',
78
+ namePart: match_array([
79
+ have_attributes(text: 'John', type_at: 'given'),
80
+ have_attributes(text: 'Huston', type_at: 'family'),
81
+ ]),
82
+ role: have_attributes(
83
+ roleTerm: match_array([
84
+ have_attributes(
85
+ text: 'drt',
86
+ type_at: 'code',
87
+ authority: 'marcrelator',
88
+ value: 'Director'
89
+ )
90
+ ]),
91
+ authority: ['marcrelator'],
92
+ code: ['drt'],
93
+ value: ['Director']
94
+ )
95
+ )
96
+ end
97
+ end
98
+
99
+ context 'with an alternate name' do
100
+ subject(:record) do
101
+ mods_record(<<-XML)
102
+ <name>
103
+ <namePart>Claudia Alta Johnson</namePart>
104
+ <alternativeName altType="nickname">
105
+ <namePart>Lady Bird Johnson</namePart>
106
+ </alternativeName>
107
+ </name>
108
+ XML
109
+ end
110
+
111
+ it 'has the expected attributes' do
112
+ expect(record.plain_name.first).to have_attributes(
113
+ namePart: have_attributes(text: 'Claudia Alta Johnson'),
114
+ alternative_name: match_array([
115
+ have_attributes(
116
+ altType: 'nickname',
117
+ namePart: have_attributes(text: 'Lady Bird Johnson')
118
+ )
119
+ ])
120
+ )
121
+ end
122
+ end
123
+
124
+ context 'with both a personal and corporate name' do
125
+ subject(:record) do
126
+ mods_record(<<-XML)
127
+ <name type='corporate'><namePart>ABC Corp</namePart></name>
128
+ <name type='personal'><namePart>Crusty</namePart></name>
129
+ XML
130
+ end
131
+
132
+ describe '#personal_name' do
133
+ it 'selects the name with the type "personal"' do
134
+ expect(record.personal_name).to match_array([
135
+ have_attributes(text: 'Crusty')
136
+ ])
137
+ end
138
+ end
139
+
140
+ describe '#corporate_name' do
141
+ it 'selects the name with the type "corporate"' do
142
+ expect(record.corporate_name).to match_array([
143
+ have_attributes(text: 'ABC Corp')
144
+ ])
145
+ end
146
+ end
147
+ end
148
+
149
+ context 'with a role with both text and a code' do
150
+ subject(:record) do
151
+ mods_record <<-XML
152
+ <name><namePart>anyone</namePart>
153
+ <role>
154
+ <roleTerm type='text' authority='marcrelator'>CreatorFake</roleTerm>
155
+ <roleTerm type='code' authority='marcrelator'>cre</roleTerm>
156
+ </role>
157
+ </name>
158
+ XML
159
+ end
160
+
161
+ it 'prefers the value of the text term' do
162
+ expect(record.plain_name.role.value).to eq ['CreatorFake']
163
+ end
164
+
165
+ it 'can return the code' do
166
+ expect(record.plain_name.role.code).to eq ['cre']
167
+ end
168
+ end
169
+
170
+ context 'with multiple roles' do
171
+ subject(:record) do
172
+ mods_record <<-XML
173
+ <name><namePart>Fats Waller</namePart>
174
+ <role>
175
+ <roleTerm type='text' authority='marcrelator'>CreatorFake</roleTerm>
176
+ <roleTerm type='code' authority='marcrelator'>cre</roleTerm>
177
+ </role>
178
+ <role>
179
+ <roleTerm type='text'>Performer</roleTerm>
180
+ </role>
181
+ </name>
182
+ XML
183
+ end
184
+
185
+ it 'returns both values' do
186
+ expect(record.plain_name.role.value).to eq ['CreatorFake', 'Performer']
187
+ end
188
+
189
+ it 'can return the code' do
190
+ expect(record.plain_name.role.code).to eq ['cre']
191
+ end
192
+ end
193
+
194
+ context 'with additional name metadata' do
195
+ subject(:record) do
196
+ mods_record <<-XML
197
+ <name>
198
+ <namePart>Exciting Prints</namePart>
199
+ <affiliation>whatever</affiliation>
200
+ <description>anything</description>
201
+ <role><roleTerm type='text'>some role</roleTerm></role>
202
+ </name>
203
+ XML
204
+ end
205
+
206
+ describe '#display_value' do
207
+ it 'has the expected value' do
208
+ expect(record.plain_name.first.display_value).to eq 'Exciting Prints'
209
+ end
210
+ end
211
+ end
212
+
213
+ context 'with an empty name' do
214
+ subject(:record) do
215
+ mods_record <<-XML
216
+ <name>
217
+ <namePart></namePart>
218
+ </name>
219
+ XML
220
+ end
221
+
222
+ describe '#display_value' do
223
+ it 'is blank' do
224
+ expect(record.plain_name.first.display_value).to be_nil
225
+ end
226
+ end
227
+ end
228
+
229
+ context 'with a displayForm' do
230
+ subject(:record) do
231
+ mods_record <<-XML
232
+ <name type='personal'>
233
+ <namePart>Alterman, Eric</namePart>
234
+ <displayForm>Eric Alterman</displayForm>
235
+ </name>
236
+ XML
237
+ end
238
+
239
+ describe '#display_value' do
240
+ it 'is the displayForm' do
241
+ expect(record.plain_name.first.display_value).to eq 'Eric Alterman'
242
+ end
243
+ end
244
+ end
245
+
246
+ context 'with a record with a displayForm that includes some dates' do
247
+ subject(:record) do
248
+ mods_record <<-XML
249
+ <name>
250
+ <namePart>Woolf, Virginia</namePart>
251
+ <namePart type='date'>1882-1941</namePart>
252
+ <displayForm>Woolf, Virginia, 1882-1941</namePart>
253
+ </name>
254
+ XML
255
+ end
256
+
257
+ describe '#display_value_w_dates' do
258
+ it 'does not duplicate the dates' do
259
+ expect(record.plain_name.first.display_value).to eq 'Woolf, Virginia, 1882-1941'
260
+ expect(record.plain_name.first.display_value_w_date).to eq 'Woolf, Virginia, 1882-1941'
261
+ end
262
+ end
263
+ end
264
+
265
+ context 'with a record with a namePart for dates' do
266
+ subject(:record) do
267
+ mods_record(<<-XML)
268
+ <name>
269
+ <namePart>Suzy</namePart>
270
+ <namePart type='date'>1920-</namePart>
271
+ </name>
272
+ XML
273
+ end
274
+
275
+ it 'has the expected attributes' do
276
+ expect(record.plain_name.first).to have_attributes(
277
+ display_value: 'Suzy',
278
+ display_value_w_date: 'Suzy, 1920-'
279
+ )
280
+ end
281
+ end
282
+
283
+ context 'without a family name and given name' do
284
+ subject(:record) do
285
+ mods_record("<name type='personal'>
286
+ <namePart type='given'>John Paul</namePart>
287
+ <namePart type='termsOfAddress'>II</namePart>
288
+ <namePart type='termsOfAddress'>Pope</namePart>
289
+ <namePart type='date'>1920-2005</namePart>
290
+ </name>")
291
+ end
292
+
293
+ describe '#display_value' do
294
+ it 'just concatenates the name parts' do
295
+ expect(record.personal_name.first.display_value).to eq 'John Paul II, Pope'
296
+ end
297
+ end
298
+
299
+ describe '#display_value_w_date' do
300
+ it 'includes the dates' do
301
+ expect(record.personal_name.first.display_value_w_date).to eq 'John Paul II, Pope, 1920-2005'
302
+ end
303
+ end
304
+ end
305
+
306
+ context 'with a bunch of untyped name parts' do
307
+ subject(:record) do
308
+ mods_record("<name type='personal'>
309
+ <namePart>Crusty</namePart>
310
+ <namePart>The Clown</namePart>
311
+ <namePart type='date'>1920-2005</namePart>
312
+ </name>")
313
+ end
314
+
315
+ describe '#display_value' do
316
+ it 'concatenates the untyped name parts' do
317
+ expect(record.personal_name.first.display_value).to eq('Crusty The Clown')
318
+ end
319
+ end
320
+ end
321
+
322
+ context 'with a corporate name' do
323
+ subject(:record) do
324
+ mods_record("<name type='corporate'>
325
+ <namePart>United States</namePart>
326
+ <namePart>Court of Appeals (2nd Circuit)</namePart>
327
+ </name>")
328
+ end
329
+
330
+ it 'concatenates the untyped name parts' do
331
+ expect(record.corporate_name.first.display_value).to eq('United States Court of Appeals (2nd Circuit)')
332
+ end
333
+ end
334
+
335
+ context 'with a complex example' do
336
+ subject(:record) do
337
+ mods_record <<-XML
338
+ <name>
339
+ <namePart>Sean Connery</namePart>
340
+ <role><roleTerm type='code' authority='marcrelator'>drt</roleTerm></role>
341
+ </name>
342
+ <name>
343
+ <namePart>Pierce Brosnan</namePart>
344
+ <role>
345
+ <roleTerm type='text'>CreatorFake</roleTerm>
346
+ <roleTerm type='code' authority='marcrelator'>cre</roleTerm>
347
+ </role>
348
+ <role><roleTerm type='text' authority='marcrelator'>Actor</roleTerm></role>
349
+ </name>
350
+ <name>
351
+ <namePart>Daniel Craig</namePart>
352
+ <role>
353
+ <roleTerm type='text' authority='marcrelator'>Actor</roleTerm>
354
+ <roleTerm type='code' authority='marcrelator'>cre</roleTerm>
355
+ </role>
356
+ </name>
357
+ XML
358
+ end
359
+
360
+ it 'has the expected attributes' do
361
+ expect(record.plain_name).to match_array([
362
+ have_attributes(role: have_attributes(value: ['Director'], code: ['drt'], authority: ['marcrelator'], size: 1)),
363
+ have_attributes(role: have_attributes(value: ['CreatorFake', 'Actor'], code: ['cre'], authority: ['marcrelator', 'marcrelator'], size: 2)),
364
+ have_attributes(role: have_attributes(value: ['Actor'], code: ['cre'], authority: ['marcrelator'], size: 1)),
365
+ ])
366
+ end
367
+ end
368
+ end
@@ -0,0 +1,134 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe "Mods <originInfo> Element" do
5
+ describe "#place" do
6
+ describe "#place_term" do
7
+ context 'with a single value' do
8
+ let(:terms) do
9
+ mods_record(<<-XML).origin_info.place.placeTerm
10
+ <originInfo><place><placeTerm authority='marccountry' type='code'>fr</placeTerm></place></originInfo>
11
+ XML
12
+ end
13
+
14
+ it 'has the expected attributes' do
15
+ expect(terms.first).to have_attributes(
16
+ authority: 'marccountry',
17
+ type_at: 'code',
18
+ text: 'fr'
19
+ )
20
+ end
21
+ end
22
+
23
+ context 'with a multi-valued place' do
24
+ let(:terms) do
25
+ mods_record(<<-XML).origin_info.place.placeTerm
26
+ <originInfo>
27
+ <place><placeTerm>France</placeTerm></place>
28
+ <place><placeTerm>Italy</placeTerm></place>
29
+ </originInfo>
30
+ XML
31
+ end
32
+
33
+ it 'has elements for each place' do
34
+ expect(terms.map(&:text)).to eq ['France', 'Italy']
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ describe "#publisher" do
41
+ subject(:publishers) do
42
+ mods_record(<<-XML).origin_info.publisher
43
+ <originInfo><publisher>Olney</publisher></origin_info>
44
+ XML
45
+ end
46
+
47
+ it "should get element values" do
48
+ expect(publishers.map(&:text)).to eq(["Olney"])
49
+ end
50
+ end
51
+
52
+ describe '#as_object' do
53
+ describe '#key_dates' do
54
+ it 'should extract the date with the keyDate attribute' do
55
+ origin_info = mods_record("<originInfo><dateCreated>other date</dateCreated><dateCreated keyDate='yes'>key date</dateCreated></originInfo>").origin_info
56
+ expect(origin_info.as_object.first.key_dates.first.text).to eq 'key date'
57
+ end
58
+ it 'should extract a date range when the keyDate attribute is on the start of the range' do
59
+ origin_info = mods_record("<originInfo><dateCreated point='end'>other date</dateCreated><dateCreated keyDate='yes' point='start'>key date</dateCreated></originInfo>").origin_info
60
+ expect(origin_info.as_object.first.key_dates.map(&:text)).to eq ['key date', 'other date']
61
+ end
62
+ end
63
+ end
64
+
65
+ Mods::ORIGIN_INFO_DATE_ELEMENTS.each do |elname|
66
+ context "<#{elname}> child elements" do
67
+ it "should recognize each element" do
68
+ origin_info = mods_record("<originInfo><#{elname}>date</#{elname}></originInfo>").origin_info.send(elname.to_sym)
69
+ expect(origin_info.map(&:text)).to eq(["date"])
70
+ end
71
+ it "should recognize encoding attribute on each element" do
72
+ origin_info = mods_record("<originInfo><#{elname} encoding='foo'>date</#{elname}></originInfo>").origin_info.send(elname.to_sym)
73
+ expect(origin_info.encoding).to eq(["foo"])
74
+ end
75
+ it "should recognize keyDate attribute" do
76
+ origin_info = mods_record("<originInfo><#{elname} keyDate='foo'>date</#{elname}></originInfo>").origin_info.send(elname.to_sym)
77
+ expect(origin_info.keyDate).to eq(["foo"])
78
+ end
79
+ it "should recognize point attribute" do
80
+ # NOTE: values allowed are 'start' and 'end'
81
+ origin_info = mods_record("<originInfo><#{elname} point='foo'>date</#{elname}></originInfo>").origin_info.send(elname.to_sym)
82
+ expect(origin_info.point).to eq(["foo"])
83
+ end
84
+ it "should recognize qualifier attribute" do
85
+ origin_info = mods_record("<originInfo><#{elname} qualifier='foo'>date</#{elname}></originInfo>").origin_info.send(elname.to_sym)
86
+ expect(origin_info.qualifier).to eq(["foo"])
87
+ end
88
+ it "should recognize type attribute only on dateOther" do
89
+ origin_info = mods_record("<originInfo><#{elname} type='foo'>date</#{elname}></originInfo>").origin_info.send(elname.to_sym)
90
+ if elname == 'dateOther'
91
+ expect(origin_info.type_at).to eq(["foo"])
92
+ else
93
+ expect { origin_info.type_at}.to raise_exception(NoMethodError, /type_at/)
94
+ end
95
+ end
96
+ end # <xxxDate> child elements
97
+ end
98
+
99
+ context 'edition' do
100
+ subject(:origin_info) do
101
+ mods_record(<<-XML).origin_info
102
+ <originInfo><edition>7th ed.</edition></originInfo>
103
+ XML
104
+ end
105
+
106
+ it "gets element value" do
107
+ expect(origin_info.edition).to have_attributes(text: '7th ed.')
108
+ end
109
+ end
110
+
111
+ context "<issuance> child element" do
112
+ subject(:origin_info) do
113
+ mods_record(<<-XML).origin_info
114
+ <originInfo><issuance>monographic</issuance></originInfo>
115
+ XML
116
+ end
117
+
118
+ it "gets element value" do
119
+ expect(origin_info.issuance).to have_attributes(text: 'monographic')
120
+ end
121
+ end
122
+
123
+ context "<frequency> child element" do
124
+ subject(:origin_info) do
125
+ mods_record(<<-XML).origin_info
126
+ <originInfo><frequency authority='marcfrequency'>Annual</frequency></originInfo>
127
+ XML
128
+ end
129
+
130
+ it "has the right attributes" do
131
+ expect(origin_info.frequency).to have_attributes(text: 'Annual', authority: ['marcfrequency'])
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,162 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe "Mods <part> Element" do
4
+ context 'with a basicpart' do
5
+ subject(:part) do
6
+ mods_record("<part>
7
+ <detail>
8
+ <title>Wayfarers (Poem)</title>
9
+ </detail>
10
+ <extent unit='pages'>
11
+ <start>97</start>
12
+ <end>98</end>
13
+ </extent>
14
+ </part>").part
15
+ end
16
+
17
+ it 'has the expected attributes' do
18
+ expect(part.first).to have_attributes(
19
+ detail: match_array([
20
+ have_attributes(
21
+ title: match_array([have_attributes(text: 'Wayfarers (Poem)')]),
22
+ number: [],
23
+ )
24
+ ]),
25
+ extent: match_array([
26
+ have_attributes(
27
+ unit: 'pages',
28
+ start: have_attributes(text: '97'),
29
+ end: have_attributes(text: '98'),
30
+ )
31
+ ])
32
+ )
33
+ end
34
+ end
35
+ context 'with a part with a detail number' do
36
+ subject(:part) do
37
+ mods_record("<part>
38
+ <detail type='page number'>
39
+ <number>3</number>
40
+ </detail>
41
+ <extent unit='pages'>
42
+ <start>3</start>
43
+ </extent>
44
+ </part>").part
45
+ end
46
+
47
+ it 'has the expected attributes' do
48
+ expect(part.first).to have_attributes(
49
+ detail: match_array([
50
+ have_attributes(
51
+ type_at: 'page number',
52
+ number: match_array([have_attributes(text: '3')])
53
+ )
54
+ ]),
55
+ extent: match_array([
56
+ have_attributes(
57
+ unit: 'pages',
58
+ start: have_attributes(text: '3')
59
+ )
60
+ ])
61
+ )
62
+ end
63
+ end
64
+ context 'with a part with a number and caption' do
65
+ subject(:part) do
66
+ mods_record("<part>
67
+ <detail type='issue'>
68
+ <number>1</number>
69
+ <caption>no.</caption>
70
+ </detail>
71
+ </part>").part
72
+ end
73
+
74
+ it 'has the expected attributes' do
75
+ expect(part.first).to have_attributes(
76
+ detail: match_array([
77
+ have_attributes(
78
+ type_at: 'issue',
79
+ number: match_array([have_attributes(text: '1')]),
80
+ caption: match_array([have_attributes(text: 'no.')])
81
+ )
82
+ ])
83
+ )
84
+ end
85
+ end
86
+
87
+ context 'with a typed part' do
88
+ subject(:part) do
89
+ mods_record("<part ID='p1' order='1' type='paragraph'>anything</part>").part
90
+ end
91
+
92
+ it 'has the expected attributes' do
93
+ expect(part.first).to have_attributes(
94
+ id_at: 'p1',
95
+ order: '1',
96
+ type_at: 'paragraph',
97
+ text: 'anything'
98
+ )
99
+ end
100
+ end
101
+
102
+ context 'with a level attribute' do
103
+ subject(:part) { mods_record("<part><detail level='val'>anything</detail></part>").part }
104
+
105
+ it 'has the expected attributes' do
106
+ expect(part.first).to have_attributes(
107
+ detail: match_array([have_attributes(level: 'val')])
108
+ )
109
+ end
110
+ end
111
+
112
+ context 'with a total element' do
113
+ subject(:part) { mods_record("<part><extent><total>anything</total></extent></part>").part }
114
+
115
+ it 'has the expected attributes' do
116
+ expect(part.first).to have_attributes(
117
+ extent: match_array([have_attributes(total: match_array([have_attributes(text: 'anything')]))])
118
+ )
119
+ end
120
+ end
121
+
122
+ context 'with a list element' do
123
+ subject(:part) { mods_record("<part><extent><list>anything</list></extent></part>").part }
124
+
125
+ it 'has the expected attributes' do
126
+ expect(part.first).to have_attributes(
127
+ extent: match_array([have_attributes(list: match_array([have_attributes(text: 'anything')]))])
128
+ )
129
+ end
130
+ end
131
+
132
+ context "<date> child element" do
133
+ subject(:date) do
134
+ mods_record("<part><date encoding='w3cdtf'>1999</date></part>").part.date
135
+ end
136
+
137
+ it 'has the expected date attributes' do
138
+ expect(date.first).to have_attributes(
139
+ encoding: 'w3cdtf',
140
+ text: '1999',
141
+ point: [],
142
+ qualifier: []
143
+ )
144
+ end
145
+
146
+ it 'does not have a keyDate attribute' do
147
+ expect(date.first).not_to respond_to(:keyDate)
148
+ end
149
+ end
150
+
151
+ context "<text> child element as .text_el term" do
152
+ subject(:part) do
153
+ mods_record("<part><text type='bar' displayLabel='foo'>1999</text></part>").part
154
+ end
155
+
156
+ describe '#text_el' do
157
+ it "has the expected attributes" do
158
+ expect(part.first.text_el).to have_attributes(text: '1999', displayLabel: ['foo'], type_at: ['bar'])
159
+ end
160
+ end
161
+ end
162
+ end