mods 2.3.0 → 3.0.0.alpha1

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 +1 -5
  5. data/README.md +1 -3
  6. data/lib/mods/marc_country_codes.rb +12 -10
  7. data/lib/mods/nom_terminology.rb +109 -848
  8. data/lib/mods/origin_info.rb +3 -1
  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 +4 -4
  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} +0 -0
  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 +366 -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 +65 -47
  32. data/.coveralls.yml +0 -1
  33. data/.travis.yml +0 -12
  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 -442
  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,366 @@
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: have_attributes(
84
+ text: 'drt',
85
+ type_at: ['code'],
86
+ authority: ['marcrelator'],
87
+ value: ['Director']
88
+ ),
89
+ authority: ['marcrelator'],
90
+ code: ['drt'],
91
+ value: ['Director']
92
+ )
93
+ )
94
+ end
95
+ end
96
+
97
+ context 'with an alternate name' do
98
+ subject(:record) do
99
+ mods_record(<<-XML)
100
+ <name>
101
+ <namePart>Claudia Alta Johnson</namePart>
102
+ <alternativeName altType="nickname">
103
+ <namePart>Lady Bird Johnson</namePart>
104
+ </alternativeName>
105
+ </name>
106
+ XML
107
+ end
108
+
109
+ it 'has the expected attributes' do
110
+ expect(record.plain_name.first).to have_attributes(
111
+ namePart: have_attributes(text: 'Claudia Alta Johnson'),
112
+ alternative_name: match_array([
113
+ have_attributes(
114
+ altType: 'nickname',
115
+ namePart: have_attributes(text: 'Lady Bird Johnson')
116
+ )
117
+ ])
118
+ )
119
+ end
120
+ end
121
+
122
+ context 'with both a personal and corporate name' do
123
+ subject(:record) do
124
+ mods_record(<<-XML)
125
+ <name type='corporate'><namePart>ABC Corp</namePart></name>
126
+ <name type='personal'><namePart>Crusty</namePart></name>
127
+ XML
128
+ end
129
+
130
+ describe '#personal_name' do
131
+ it 'selects the name with the type "personal"' do
132
+ expect(record.personal_name).to match_array([
133
+ have_attributes(text: 'Crusty')
134
+ ])
135
+ end
136
+ end
137
+
138
+ describe '#corporate_name' do
139
+ it 'selects the name with the type "corporate"' do
140
+ expect(record.corporate_name).to match_array([
141
+ have_attributes(text: 'ABC Corp')
142
+ ])
143
+ end
144
+ end
145
+ end
146
+
147
+ context 'with a role with both text and a code' do
148
+ subject(:record) do
149
+ mods_record <<-XML
150
+ <name><namePart>anyone</namePart>
151
+ <role>
152
+ <roleTerm type='text' authority='marcrelator'>CreatorFake</roleTerm>
153
+ <roleTerm type='code' authority='marcrelator'>cre</roleTerm>
154
+ </role>
155
+ </name>
156
+ XML
157
+ end
158
+
159
+ it 'prefers the value of the text term' do
160
+ expect(record.plain_name.role.value).to eq ['CreatorFake']
161
+ end
162
+
163
+ it 'can return the code' do
164
+ expect(record.plain_name.role.code).to eq ['cre']
165
+ end
166
+ end
167
+
168
+ context 'with multiple roles' do
169
+ subject(:record) do
170
+ mods_record <<-XML
171
+ <name><namePart>Fats Waller</namePart>
172
+ <role>
173
+ <roleTerm type='text' authority='marcrelator'>CreatorFake</roleTerm>
174
+ <roleTerm type='code' authority='marcrelator'>cre</roleTerm>
175
+ </role>
176
+ <role>
177
+ <roleTerm type='text'>Performer</roleTerm>
178
+ </role>
179
+ </name>
180
+ XML
181
+ end
182
+
183
+ it 'returns both values' do
184
+ expect(record.plain_name.role.value).to eq ['CreatorFake', 'Performer']
185
+ end
186
+
187
+ it 'can return the code' do
188
+ expect(record.plain_name.role.code).to eq ['cre']
189
+ end
190
+ end
191
+
192
+ context 'with additional name metadata' do
193
+ subject(:record) do
194
+ mods_record <<-XML
195
+ <name>
196
+ <namePart>Exciting Prints</namePart>
197
+ <affiliation>whatever</affiliation>
198
+ <description>anything</description>
199
+ <role><roleTerm type='text'>some role</roleTerm></role>
200
+ </name>
201
+ XML
202
+ end
203
+
204
+ describe '#display_value' do
205
+ it 'has the expected value' do
206
+ expect(record.plain_name.first.display_value).to eq 'Exciting Prints'
207
+ end
208
+ end
209
+ end
210
+
211
+ context 'with an empty name' do
212
+ subject(:record) do
213
+ mods_record <<-XML
214
+ <name>
215
+ <namePart></namePart>
216
+ </name>
217
+ XML
218
+ end
219
+
220
+ describe '#display_value' do
221
+ it 'is blank' do
222
+ expect(record.plain_name.first.display_value).to be_nil
223
+ end
224
+ end
225
+ end
226
+
227
+ context 'with a displayForm' do
228
+ subject(:record) do
229
+ mods_record <<-XML
230
+ <name type='personal'>
231
+ <namePart>Alterman, Eric</namePart>
232
+ <displayForm>Eric Alterman</displayForm>
233
+ </name>
234
+ XML
235
+ end
236
+
237
+ describe '#display_value' do
238
+ it 'is the displayForm' do
239
+ expect(record.plain_name.first.display_value).to eq 'Eric Alterman'
240
+ end
241
+ end
242
+ end
243
+
244
+ context 'with a record with a displayForm that includes some dates' do
245
+ subject(:record) do
246
+ mods_record <<-XML
247
+ <name>
248
+ <namePart>Woolf, Virginia</namePart>
249
+ <namePart type='date'>1882-1941</namePart>
250
+ <displayForm>Woolf, Virginia, 1882-1941</namePart>
251
+ </name>
252
+ XML
253
+ end
254
+
255
+ describe '#display_value_w_dates' do
256
+ it 'does not duplicate the dates' do
257
+ expect(record.plain_name.first.display_value).to eq 'Woolf, Virginia, 1882-1941'
258
+ expect(record.plain_name.first.display_value_w_date).to eq 'Woolf, Virginia, 1882-1941'
259
+ end
260
+ end
261
+ end
262
+
263
+ context 'with a record with a namePart for dates' do
264
+ subject(:record) do
265
+ mods_record(<<-XML)
266
+ <name>
267
+ <namePart>Suzy</namePart>
268
+ <namePart type='date'>1920-</namePart>
269
+ </name>
270
+ XML
271
+ end
272
+
273
+ it 'has the expected attributes' do
274
+ expect(record.plain_name.first).to have_attributes(
275
+ display_value: 'Suzy',
276
+ display_value_w_date: 'Suzy, 1920-'
277
+ )
278
+ end
279
+ end
280
+
281
+ context 'without a family name and given name' do
282
+ subject(:record) do
283
+ mods_record("<name type='personal'>
284
+ <namePart type='given'>John Paul</namePart>
285
+ <namePart type='termsOfAddress'>II</namePart>
286
+ <namePart type='termsOfAddress'>Pope</namePart>
287
+ <namePart type='date'>1920-2005</namePart>
288
+ </name>")
289
+ end
290
+
291
+ describe '#display_value' do
292
+ it 'just concatenates the name parts' do
293
+ expect(record.personal_name.first.display_value).to eq 'John Paul II, Pope'
294
+ end
295
+ end
296
+
297
+ describe '#display_value_w_date' do
298
+ it 'includes the dates' do
299
+ expect(record.personal_name.first.display_value_w_date).to eq 'John Paul II, Pope, 1920-2005'
300
+ end
301
+ end
302
+ end
303
+
304
+ context 'with a bunch of untyped name parts' do
305
+ subject(:record) do
306
+ mods_record("<name type='personal'>
307
+ <namePart>Crusty</namePart>
308
+ <namePart>The Clown</namePart>
309
+ <namePart type='date'>1920-2005</namePart>
310
+ </name>")
311
+ end
312
+
313
+ describe '#display_value' do
314
+ it 'concatenates the untyped name parts' do
315
+ expect(record.personal_name.first.display_value).to eq('Crusty The Clown')
316
+ end
317
+ end
318
+ end
319
+
320
+ context 'with a corporate name' do
321
+ subject(:record) do
322
+ mods_record("<name type='corporate'>
323
+ <namePart>United States</namePart>
324
+ <namePart>Court of Appeals (2nd Circuit)</namePart>
325
+ </name>")
326
+ end
327
+
328
+ it 'concatenates the untyped name parts' do
329
+ expect(record.corporate_name.first.display_value).to eq('United States Court of Appeals (2nd Circuit)')
330
+ end
331
+ end
332
+
333
+ context 'with a complex example' do
334
+ subject(:record) do
335
+ mods_record <<-XML
336
+ <name>
337
+ <namePart>Sean Connery</namePart>
338
+ <role><roleTerm type='code' authority='marcrelator'>drt</roleTerm></role>
339
+ </name>
340
+ <name>
341
+ <namePart>Pierce Brosnan</namePart>
342
+ <role>
343
+ <roleTerm type='text'>CreatorFake</roleTerm>
344
+ <roleTerm type='code' authority='marcrelator'>cre</roleTerm>
345
+ </role>
346
+ <role><roleTerm type='text' authority='marcrelator'>Actor</roleTerm></role>
347
+ </name>
348
+ <name>
349
+ <namePart>Daniel Craig</namePart>
350
+ <role>
351
+ <roleTerm type='text' authority='marcrelator'>Actor</roleTerm>
352
+ <roleTerm type='code' authority='marcrelator'>cre</roleTerm>
353
+ </role>
354
+ </name>
355
+ XML
356
+ end
357
+
358
+ it 'has the expected attributes' do
359
+ expect(record.plain_name).to match_array([
360
+ have_attributes(role: have_attributes(value: ['Director'], code: ['drt'], authority: ['marcrelator'], size: 1)),
361
+ have_attributes(role: have_attributes(value: ['CreatorFake', 'Actor'], code: ['cre'], authority: ['marcrelator', 'marcrelator'], size: 2)),
362
+ have_attributes(role: have_attributes(value: ['Actor'], code: ['cre'], authority: ['marcrelator'], size: 1)),
363
+ ])
364
+ end
365
+ end
366
+ 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