mods 0.0.4 → 0.0.5
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.
- data/README.rdoc +1 -0
- data/lib/mods.rb +2 -1
- data/lib/mods/name.rb +2 -3
- data/lib/mods/nom_terminology.rb +100 -6
- data/lib/mods/subject.rb +18 -0
- data/lib/mods/title_info.rb +5 -5
- data/lib/mods/version.rb +1 -1
- data/spec/name_spec.rb +5 -5
- data/spec/subject_spec.rb +440 -0
- data/spec/title_spec.rb +2 -2
- data/spec/top_level_elmnts_simple_spec.rb +7 -0
- metadata +7 -4
data/README.rdoc
CHANGED
@@ -37,6 +37,7 @@ TODO: Write usage instructions here
|
|
37
37
|
|
38
38
|
== Releases
|
39
39
|
|
40
|
+
0.0.5 implement subject, change a few constants
|
40
41
|
0.0.4 implement language, location, origin_info, physical_description
|
41
42
|
0.0.3 use nom-xml gem and make this more nokogiri-ish; implement name, title, and simple top level elements with no subelements
|
42
43
|
0.0.2 Set up rake tasks, publishing rdoc, and continuous integration.
|
data/lib/mods.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'mods/constants'
|
2
|
+
require 'mods/nom_terminology'
|
2
3
|
require 'mods/marc_relator_codes'
|
3
4
|
require 'mods/name'
|
4
|
-
require 'mods/nom_terminology'
|
5
5
|
require 'mods/reader'
|
6
6
|
require 'mods/record'
|
7
|
+
require 'mods/subject'
|
7
8
|
require 'mods/title_info'
|
8
9
|
require 'mods/version'
|
9
10
|
|
data/lib/mods/name.rb
CHANGED
@@ -2,11 +2,10 @@ module Mods
|
|
2
2
|
|
3
3
|
class Name
|
4
4
|
|
5
|
-
|
6
|
-
SUBELEMENTS = ['namePart', 'displayForm', 'affiliation', 'role', 'description']
|
5
|
+
CHILD_ELEMENTS = ['namePart', 'displayForm', 'affiliation', 'role', 'description']
|
7
6
|
|
8
7
|
# attributes on name node
|
9
|
-
ATTRIBUTES = ['type', '
|
8
|
+
ATTRIBUTES = Mods::AUTHORITY_ATTRIBS + ['type', 'displayLabel', 'usage', 'altRepGroup', 'nameTitleGroup']
|
10
9
|
|
11
10
|
# valid values for type attribute on name node <name type="val"/>
|
12
11
|
TYPES = ['personal', 'corporate', 'conference', 'family']
|
data/lib/mods/nom_terminology.rb
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
module Mods
|
2
2
|
|
3
|
+
# from: http://www.loc.gov/standards/mods/v3/mods-userguide-generalapp.html
|
4
|
+
|
5
|
+
LANG_ATTRIBS = ['lang', 'xml:lang', 'script', 'transliteration']
|
6
|
+
|
7
|
+
LINKING_ATTRIBS = ['xlink', 'ID']
|
8
|
+
|
9
|
+
DATE_ATTRIBS = ['encoding', 'point', 'keyDate', 'qualifier']
|
10
|
+
ENCODING_ATTRIB_VALUES = ['w3cdtf', 'iso8601', 'marc']
|
11
|
+
POINT_ATTRIB_VALUES = ['start', 'end']
|
12
|
+
KEY_DATE_ATTRIB_VALUEs = ['yes']
|
13
|
+
QUALIFIER_ATTRIB_VALUES = ['approximate', 'inferred', 'questionable']
|
14
|
+
|
15
|
+
AUTHORITY_ATTRIBS = ['authority', 'authorityURI', 'valueURI']
|
16
|
+
|
3
17
|
class Record
|
4
18
|
|
5
19
|
# set the NOM terminology; do NOT use namespaces
|
@@ -18,15 +32,23 @@ module Mods
|
|
18
32
|
# note - titleInfo can be a top level element or a sub-element of relatedItem
|
19
33
|
# (<titleInfo> as subelement of <subject> is not part of the MODS namespace)
|
20
34
|
|
21
|
-
t.title_info :path => '/mods/titleInfo'
|
22
|
-
|
35
|
+
t.title_info :path => '/mods/titleInfo'
|
36
|
+
|
37
|
+
t._title_info :path => '//titleInfo' do |n|
|
38
|
+
Mods::TitleInfo::ATTRIBUTES.each { |attr_name|
|
39
|
+
if attr_name != 'type'
|
40
|
+
n.send attr_name, :path => "@#{attr_name}", :accessor => lambda { |a| a.text }
|
41
|
+
else
|
42
|
+
n.type_at :path => "@#{attr_name}", :accessor => lambda { |a| a.text }
|
43
|
+
end
|
44
|
+
}
|
23
45
|
n.title :path => 'title'
|
24
46
|
n.subTitle :path => 'subTitle'
|
25
47
|
n.nonSort :path => 'nonSort'
|
26
48
|
n.partNumber :path => 'partNumber'
|
27
49
|
n.partName :path => 'partName'
|
28
50
|
n.sort_title :path => '.', :accessor => lambda { |node|
|
29
|
-
if node.type_at
|
51
|
+
if node.type_at != "alternative" || (node.type_at == "alternative" && mods_ng_xml.xpath('/mods/titleInfo').size == 1)
|
30
52
|
node.title.text + (!node.subTitle.text.empty? ? "#{@title_delimiter}#{node.subTitle.text}" : "" )
|
31
53
|
end
|
32
54
|
}
|
@@ -36,13 +58,13 @@ module Mods
|
|
36
58
|
(!node.subTitle.text.empty? ? "#{@title_delimiter}#{node.subTitle.text}" : "" )
|
37
59
|
}
|
38
60
|
n.short_title :path => '.', :accessor => lambda { |node|
|
39
|
-
if node.type_at
|
61
|
+
if node.type_at != "alternative"
|
40
62
|
(!node.nonSort.text.empty? ? "#{node.nonSort.text} " : "" ) +
|
41
63
|
node.title.text
|
42
64
|
end
|
43
65
|
}
|
44
66
|
n.alternative_title :path => '.', :accessor => lambda { |node|
|
45
|
-
if node.type_at
|
67
|
+
if node.type_at == "alternative"
|
46
68
|
(!node.nonSort.text.empty? ? "#{node.nonSort.text} " : "" ) +
|
47
69
|
node.title.text
|
48
70
|
end
|
@@ -57,8 +79,9 @@ module Mods
|
|
57
79
|
|
58
80
|
|
59
81
|
# NAME ------------------------------------------------------------------------------------
|
82
|
+
t.plain_name :path => '/mods/name'
|
60
83
|
|
61
|
-
t.
|
84
|
+
t._plain_name :path => '//name' do |n|
|
62
85
|
|
63
86
|
Mods::Name::ATTRIBUTES.each { |attr_name|
|
64
87
|
if attr_name != 'type'
|
@@ -163,6 +186,77 @@ module Mods
|
|
163
186
|
end
|
164
187
|
end
|
165
188
|
|
189
|
+
# SUBJECT -----------------------------------------------------------------------------
|
190
|
+
t.subject :path => '/mods/subject' do |n|
|
191
|
+
Mods::AUTHORITY_ATTRIBS.each { |attr_name|
|
192
|
+
n.send attr_name, :path => "@#{attr_name}", :accessor => lambda { |a| a.text }
|
193
|
+
}
|
194
|
+
n.topic :path => 'topic' do |n|
|
195
|
+
Mods::AUTHORITY_ATTRIBS.each { |attr_name|
|
196
|
+
n.send attr_name, :path => "@#{attr_name}", :accessor => lambda { |a| a.text }
|
197
|
+
}
|
198
|
+
end
|
199
|
+
n.geographic :path => 'geographic' do |n|
|
200
|
+
Mods::AUTHORITY_ATTRIBS.each { |attr_name|
|
201
|
+
n.send attr_name, :path => "@#{attr_name}", :accessor => lambda { |a| a.text }
|
202
|
+
}
|
203
|
+
end
|
204
|
+
n.temporal :path => 'temporal' do |n|
|
205
|
+
n.encoding :path => 'encoding'
|
206
|
+
n.point :path => 'point'
|
207
|
+
n.keyDate :path => 'keyDate'
|
208
|
+
n.qualifier :path => 'qualifier'
|
209
|
+
Mods::AUTHORITY_ATTRIBS.each { |attr_name|
|
210
|
+
n.send attr_name, :path => "@#{attr_name}", :accessor => lambda { |a| a.text }
|
211
|
+
}
|
212
|
+
Mods::DATE_ATTRIBS.each { |attr_name|
|
213
|
+
n.send attr_name, :path => "@#{attr_name}", :accessor => lambda { |a| a.text }
|
214
|
+
}
|
215
|
+
end
|
216
|
+
n.titleInfo :path => 'titleInfo' do |t|
|
217
|
+
Mods::AUTHORITY_ATTRIBS.each { |attr_name|
|
218
|
+
t.send attr_name, :path => "@#{attr_name}", :accessor => lambda { |a| a.text }
|
219
|
+
}
|
220
|
+
end
|
221
|
+
# Note: 'name' is used by Nokogiri
|
222
|
+
n.name_ :path => 'name' do |t|
|
223
|
+
Mods::AUTHORITY_ATTRIBS.each { |attr_name|
|
224
|
+
t.send attr_name, :path => "@#{attr_name}", :accessor => lambda { |a| a.text }
|
225
|
+
}
|
226
|
+
end
|
227
|
+
n.geographicCode :path => 'geographicCode' do |g|
|
228
|
+
Mods::AUTHORITY_ATTRIBS.each { |attr_name|
|
229
|
+
g.send attr_name, :path => "@#{attr_name}", :accessor => lambda { |a| a.text }
|
230
|
+
}
|
231
|
+
end
|
232
|
+
n.genre :path => 'genre' do |n|
|
233
|
+
Mods::AUTHORITY_ATTRIBS.each { |attr_name|
|
234
|
+
n.send attr_name, :path => "@#{attr_name}", :accessor => lambda { |a| a.text }
|
235
|
+
}
|
236
|
+
end
|
237
|
+
n.hierarchicalGeographic :path => 'hierarchicalGeographic' do |n|
|
238
|
+
Mods::Subject::HIER_GEO_CHILD_ELEMENTS.each { |elname|
|
239
|
+
n.send elname, :path => "#{elname}"
|
240
|
+
}
|
241
|
+
Mods::AUTHORITY_ATTRIBS.each { |attr_name|
|
242
|
+
n.send attr_name, :path => "@#{attr_name}", :accessor => lambda { |a| a.text }
|
243
|
+
}
|
244
|
+
end
|
245
|
+
n.cartographics :path => 'cartographics' do |n|
|
246
|
+
n.scale :path => 'scale'
|
247
|
+
n.projection :path => 'projection'
|
248
|
+
n.coordinates :path => 'coordinates'
|
249
|
+
Mods::Subject::CARTOGRAPHICS_CHILD_ELEMENTS.each { |elname|
|
250
|
+
n.send elname, :path => "#{elname}"
|
251
|
+
}
|
252
|
+
end
|
253
|
+
n.occupation :path => 'occupation' do |n|
|
254
|
+
Mods::AUTHORITY_ATTRIBS.each { |attr_name|
|
255
|
+
n.send attr_name, :path => "@#{attr_name}", :accessor => lambda { |a| a.text }
|
256
|
+
}
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
166
260
|
end # terminology
|
167
261
|
|
168
262
|
mods_ng_xml.nom!
|
data/lib/mods/subject.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Mods
|
2
|
+
|
3
|
+
class Subject
|
4
|
+
|
5
|
+
CHILD_ELEMENTS = ['topic', 'geographic', 'temporal', 'titleInfo', 'name', 'genre', 'hierarchicalGeographic', 'cartographics', 'geographicCode', 'occupation']
|
6
|
+
|
7
|
+
# attributes on subject node
|
8
|
+
ATTRIBUTES = Mods::LANG_ATTRIBS + Mods::LINKING_ATTRIBS + ['authority']
|
9
|
+
|
10
|
+
HIER_GEO_CHILD_ELEMENTS = ['continent', 'country', 'province', 'region', 'state', 'territory', 'county', 'city', 'citySection', 'island', 'area', 'extraterrestrialArea']
|
11
|
+
|
12
|
+
CARTOGRAPHICS_CHILD_ELEMENTS = ['coordinates', 'scale', 'projection']
|
13
|
+
|
14
|
+
GEO_CODE_AUTHORITIES = ['marcgac, marccountry, iso3166']
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/lib/mods/title_info.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
module Mods
|
2
|
-
|
2
|
+
|
3
3
|
class TitleInfo
|
4
|
-
# attr_reader :ng_node
|
5
4
|
|
6
|
-
|
7
|
-
SUBELEMENTS = ['title', 'subTitle', 'partNumber', 'partName', 'nonSort']
|
5
|
+
CHILD_ELEMENTS = ['title', 'subTitle', 'partNumber', 'partName', 'nonSort']
|
8
6
|
|
9
7
|
# attributes on titleInfo node
|
10
|
-
ATTRIBUTES = ['type', '
|
8
|
+
ATTRIBUTES = Mods::AUTHORITY_ATTRIBS + ['type', 'displayLabel', 'supplied', 'usage', 'altRepGroup', 'nameTitleGroup']
|
11
9
|
|
12
10
|
# valid values for type attribute on titleInfo node <titleInfo type="val">
|
13
11
|
TYPES = ['abbreviated', 'translated', 'alternative', 'uniform']
|
14
12
|
|
15
13
|
DEFAULT_TITLE_DELIM = ' '
|
16
14
|
|
15
|
+
# attr_reader :ng_node
|
16
|
+
|
17
17
|
# @param (Nokogiri::XML::Node) mods:titleInfo node
|
18
18
|
# def initialize(title_info_node)
|
19
19
|
# @ng_node = title_info_node
|
data/lib/mods/version.rb
CHANGED
data/spec/name_spec.rb
CHANGED
@@ -27,7 +27,7 @@ describe "Mods <name> Element" do
|
|
27
27
|
context "personal name" do
|
28
28
|
|
29
29
|
it "should recognize child elements" do
|
30
|
-
Mods::Name::
|
30
|
+
Mods::Name::CHILD_ELEMENTS.reject{|e| e == "role"}.each { |e|
|
31
31
|
@mods_rec.from_str("<mods><name type='personal'><#{e}>oofda</#{e}></name></mods>")
|
32
32
|
if e == 'description'
|
33
33
|
@mods_rec.personal_name.description_el.text.should == 'oofda'
|
@@ -161,7 +161,7 @@ describe "Mods <name> Element" do
|
|
161
161
|
end
|
162
162
|
|
163
163
|
it "should recognize child elements" do
|
164
|
-
Mods::Name::
|
164
|
+
Mods::Name::CHILD_ELEMENTS.reject{|e| e == "role" }.each { |e|
|
165
165
|
@mods_rec.from_str("<mods><name type='corporate'><#{e}>oofda</#{e}></name></mods>")
|
166
166
|
if e == 'description'
|
167
167
|
@mods_rec.corporate_name.description_el.text.should == 'oofda'
|
@@ -204,7 +204,7 @@ describe "Mods <name> Element" do
|
|
204
204
|
context "(plain) <name> element terminology pieces" do
|
205
205
|
|
206
206
|
it "should recognize child elements" do
|
207
|
-
Mods::Name::
|
207
|
+
Mods::Name::CHILD_ELEMENTS.reject{|e| e == "role"}.each { |e|
|
208
208
|
@mods_rec.from_str("<mods><name><#{e}>oofda</#{e}></name></mods>")
|
209
209
|
if e == 'description'
|
210
210
|
@mods_rec.plain_name.description_el.text.should == 'oofda'
|
@@ -225,7 +225,7 @@ describe "Mods <name> Element" do
|
|
225
225
|
}
|
226
226
|
end
|
227
227
|
|
228
|
-
context "namePart
|
228
|
+
context "namePart child element" do
|
229
229
|
it "should recognize type attribute on namePart element" do
|
230
230
|
Mods::Name::NAME_PART_TYPES.each { |t|
|
231
231
|
@mods_rec.from_str("<mods><name><namePart type='#{t}'>hi</namePart></name></mods>")
|
@@ -234,7 +234,7 @@ describe "Mods <name> Element" do
|
|
234
234
|
end
|
235
235
|
end
|
236
236
|
|
237
|
-
context "role
|
237
|
+
context "role child element" do
|
238
238
|
it "should get role type" do
|
239
239
|
@mods_rec.from_str(@mods_w_pers_name_role)
|
240
240
|
@mods_rec.plain_name.role.type_at.should == ["text"]
|
@@ -0,0 +1,440 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Mods <subject> Element" do
|
4
|
+
before(:all) do
|
5
|
+
@mods_rec = Mods::Record.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should do something intelligent with duplicate values" do
|
9
|
+
pending "to be implemented"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should do some date parsing of temporal element based on encoding" do
|
13
|
+
pending "to be implemented"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "authority designation on the <subject> element should trickle down to child elements" do
|
17
|
+
pending "to be implemented"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should subject personal name dates should be cleaned up???" do
|
21
|
+
pending "to be implemented"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should translate the geographicCodes" do
|
25
|
+
pending "to be implemented"
|
26
|
+
end
|
27
|
+
|
28
|
+
context "names" do
|
29
|
+
before(:all) do
|
30
|
+
@both_types = @mods_rec.from_str('<mods><subject>
|
31
|
+
<name type="personal">
|
32
|
+
<namePart>Bridgens, R.P</namePart>
|
33
|
+
</name>
|
34
|
+
</subject><subject authority="lcsh">
|
35
|
+
<name type="corporate">
|
36
|
+
<namePart>Britton & Rey.</namePart>
|
37
|
+
</name>
|
38
|
+
</subject></mods>').subject.name
|
39
|
+
@pers_name = @mods_rec.from_str('<mods><subject>
|
40
|
+
<name type="personal" authority="ingest">
|
41
|
+
<namePart type="family">Edward VI , king of England, </namePart>
|
42
|
+
<displayForm>Edward VI , king of England, 1537-1553</displayForm>
|
43
|
+
</name></subject></mods>').subject.name
|
44
|
+
@mult_pers_name = @mods_rec.from_str('<mods><subject authority="lcsh">
|
45
|
+
<name type="personal">
|
46
|
+
<namePart>Baker, George H</namePart>
|
47
|
+
<role>
|
48
|
+
<roleTerm type="text">lithographer.</roleTerm>
|
49
|
+
</role>
|
50
|
+
</name>
|
51
|
+
</subject><subject>
|
52
|
+
<name type="personal">
|
53
|
+
<namePart>Beach, Ghilion</namePart>
|
54
|
+
<role>
|
55
|
+
<roleTerm type="text">publisher.</roleTerm>
|
56
|
+
</role>
|
57
|
+
</name>
|
58
|
+
</subject><subject>
|
59
|
+
<name type="personal">
|
60
|
+
<namePart>Bridgens, R.P</namePart>
|
61
|
+
</name>
|
62
|
+
</subject><subject authority="lcsh">
|
63
|
+
<name type="personal">
|
64
|
+
<namePart>Couts, Cave Johnson</namePart>
|
65
|
+
<namePart type="date">1821-1874</namePart>
|
66
|
+
</name>
|
67
|
+
</subject><subject authority="lcsh">
|
68
|
+
<name type="personal">
|
69
|
+
<namePart>Kuchel, Charles Conrad</namePart>
|
70
|
+
<namePart type="date">b. 1820</namePart>
|
71
|
+
</name>
|
72
|
+
</subject><subject authority="lcsh">
|
73
|
+
<name type="personal">
|
74
|
+
<namePart>Nahl, Charles Christian</namePart>
|
75
|
+
<namePart type="date">1818-1878</namePart>
|
76
|
+
</name>
|
77
|
+
</subject><subject authority="lcsh">
|
78
|
+
<name type="personal">
|
79
|
+
<namePart>Swasey, W. F. (William F.)</namePart>
|
80
|
+
</name></subject></mods>').subject.name
|
81
|
+
@mult_corp_name = @mods_rec.from_str('<mods><subject authority="lcsh">
|
82
|
+
<name type="corporate">
|
83
|
+
<namePart>Britton & Rey.</namePart>
|
84
|
+
</name>
|
85
|
+
</subject><subject>
|
86
|
+
<name type="corporate">
|
87
|
+
<namePart>Gray (W. Vallance) & C.B. Gifford,</namePart>
|
88
|
+
<role>
|
89
|
+
<roleTerm type="text">lithographers.</roleTerm>
|
90
|
+
</role>
|
91
|
+
</name></subject></mods>').subject.name
|
92
|
+
end
|
93
|
+
it "should be able to identify corporate names" do
|
94
|
+
pending "to be implemented"
|
95
|
+
end
|
96
|
+
it "should be able to identify personal names" do
|
97
|
+
pending "to be implemented"
|
98
|
+
end
|
99
|
+
it "should be able to identify roles associated with a name" do
|
100
|
+
pending "to be implemented"
|
101
|
+
end
|
102
|
+
it "should be able to identify dates associated with a name" do
|
103
|
+
pending "to be implemented"
|
104
|
+
end
|
105
|
+
it "should do the appropriate thing with the role for the value of a name" do
|
106
|
+
pending "to be implemented"
|
107
|
+
end
|
108
|
+
it "should do the appropriate thing with the date for the value of a name" do
|
109
|
+
pending "to be implemented"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context "basic subject terminology pieces" do
|
114
|
+
before(:all) do
|
115
|
+
@four_subjects = @mods_rec.from_str('<mods><subject authority="lcsh">
|
116
|
+
<geographic>San Francisco (Calif.)</geographic>
|
117
|
+
<topic>History</topic>
|
118
|
+
<genre>Pictorial works</genre>
|
119
|
+
</subject>
|
120
|
+
<subject authority="lcsh">
|
121
|
+
<geographic>San Diego (Calif.)</geographic>
|
122
|
+
<topic>History</topic>
|
123
|
+
<genre>Pictorial works</genre>
|
124
|
+
</subject>
|
125
|
+
<subject authority="lcsh">
|
126
|
+
<topic>History</topic>
|
127
|
+
<genre>Pictorial works</genre>
|
128
|
+
</subject>
|
129
|
+
<subject authority="lcsh">
|
130
|
+
<geographic>San Luis Rey (Calif.)</geographic>
|
131
|
+
<genre>Pictorial works</genre>
|
132
|
+
</subject></mods>').subject
|
133
|
+
@geo_code_subject = @mods_rec.from_str('<mods><subject>
|
134
|
+
<geographicCode authority="marcgac">f------</geographicCode></subject></mods>').subject
|
135
|
+
@lcsh_subject = @mods_rec.from_str('<mods><subject authority="lcsh">
|
136
|
+
<geographic>Africa</geographic>
|
137
|
+
<genre>Maps</genre>
|
138
|
+
<temporal>500-1400</temporal></subject></mods>').subject
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should be a NodeSet" do
|
142
|
+
@four_subjects.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
143
|
+
@lcsh_subject.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
144
|
+
end
|
145
|
+
it "should have as many members as there are <subject> elements in the xml" do
|
146
|
+
@four_subjects.size.should == 4
|
147
|
+
@lcsh_subject.size.should == 1
|
148
|
+
end
|
149
|
+
it "should recognize authority attribute on <subject> element" do
|
150
|
+
['lcsh', 'ingest', 'lctgm'].each { |a|
|
151
|
+
@mods_rec.from_str("<mods><subject authority='#{a}'><topic>Ruler, English.</topic></subject></mods>").subject.authority.should == [a]
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
context "<topic> child element" do
|
156
|
+
before(:all) do
|
157
|
+
topic = '<mods><subject authority="lcsh"><topic>History</topic></subject></mods>'
|
158
|
+
@topic_simple = @mods_rec.from_str(topic).subject.topic
|
159
|
+
multi_topic = '<mods><subject>
|
160
|
+
<topic>California as an island--Maps--1662?</topic>
|
161
|
+
<topic>North America--Maps--To 1800</topic>
|
162
|
+
<topic>North America--Maps--1662?</topic>
|
163
|
+
</subject></mods>'
|
164
|
+
@multi_topic = @mods_rec.from_str(multi_topic).subject.topic
|
165
|
+
end
|
166
|
+
it "should be a NodeSet" do
|
167
|
+
@topic_simple.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
168
|
+
@multi_topic.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
169
|
+
end
|
170
|
+
it "topic NodeSet should have as many Nodes as there are <topic> elements in the xml" do
|
171
|
+
@topic_simple.size.should == 1
|
172
|
+
@multi_topic.size.should == 3
|
173
|
+
@four_subjects.topic.size.should == 3
|
174
|
+
@geo_code_subject.topic.size.should == 0
|
175
|
+
end
|
176
|
+
it "text should get element value" do
|
177
|
+
@topic_simple.text.should == "History"
|
178
|
+
@multi_topic.text.should include("California as an island--Maps--1662?")
|
179
|
+
@multi_topic.text.should include("North America--Maps--To 1800")
|
180
|
+
@multi_topic.text.should include("North America--Maps--1662?")
|
181
|
+
@four_subjects.topic.text.should include("History")
|
182
|
+
end
|
183
|
+
end # <topic>
|
184
|
+
|
185
|
+
context "<geographic> child element" do
|
186
|
+
it "should be a NodeSet" do
|
187
|
+
@four_subjects.geographic.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
188
|
+
@lcsh_subject.geographic.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
189
|
+
@geo_code_subject.geographic.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
190
|
+
end
|
191
|
+
it "geographic NodeSet should have as many Nodes as there are <geographic> elements in the xml" do
|
192
|
+
@four_subjects.geographic.size.should == 3
|
193
|
+
@lcsh_subject.geographic.size.should == 1
|
194
|
+
@geo_code_subject.geographic.size.should == 0
|
195
|
+
end
|
196
|
+
it "text should get element value" do
|
197
|
+
@four_subjects.geographic.text.should include("San Francisco (Calif.)")
|
198
|
+
@four_subjects.geographic.text.should include("San Diego (Calif.)")
|
199
|
+
@four_subjects.geographic.text.should include("San Luis Rey (Calif.)")
|
200
|
+
end
|
201
|
+
it "should not include <geographicCode> element" do
|
202
|
+
@geo_code_subject.geographic.size.should == 0
|
203
|
+
end
|
204
|
+
end # <geographic>
|
205
|
+
|
206
|
+
context "<temporal> child element" do
|
207
|
+
before(:all) do
|
208
|
+
@temporal = @mods_rec.from_str('<mods><subject>
|
209
|
+
<temporal encoding="iso8601">20010203T040506+0700</temporal>
|
210
|
+
<!-- <temporal encoding="iso8601">197505</temporal> -->
|
211
|
+
</subject></mods>').subject.temporal
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should recognize the date attributes" do
|
215
|
+
@temporal.encoding.should == ['iso8601']
|
216
|
+
Mods::DATE_ATTRIBS.each { |a|
|
217
|
+
@mods_rec.from_str("<mods><subject><temporal #{a}='val'>now</temporal></subject></mods>").subject.temporal.send(a.to_sym).should == ['val']
|
218
|
+
}
|
219
|
+
end
|
220
|
+
it "should be a NodeSet" do
|
221
|
+
@lcsh_subject.temporal.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
222
|
+
@temporal.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
223
|
+
end
|
224
|
+
it "temporal NodeSet should have as many Nodes as there are <temporal> elements in the xml" do
|
225
|
+
@lcsh_subject.temporal.size.should == 1
|
226
|
+
@temporal.size.should == 1
|
227
|
+
end
|
228
|
+
it "text should get element value" do
|
229
|
+
@lcsh_subject.temporal.map { |n| n.text }.should == ['500-1400']
|
230
|
+
@temporal.map { |n| n.text }.should == ['20010203T040506+0700']
|
231
|
+
end
|
232
|
+
end # <temporal>
|
233
|
+
|
234
|
+
context "<genre> child element" do
|
235
|
+
it "should be a NodeSet" do
|
236
|
+
@lcsh_subject.genre.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
237
|
+
@four_subjects.genre.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
238
|
+
end
|
239
|
+
it "genre NodeSet should have as many Nodes as there are <genre> elements in the xml" do
|
240
|
+
@lcsh_subject.genre.size.should == 1
|
241
|
+
@four_subjects.genre.size.should == 4
|
242
|
+
end
|
243
|
+
it "text should get element value" do
|
244
|
+
@lcsh_subject.genre.map { |n| n.text }.should == ['Maps']
|
245
|
+
@four_subjects.genre.map { |n| n.text }.should include("Pictorial works")
|
246
|
+
end
|
247
|
+
end # <genre>
|
248
|
+
|
249
|
+
context "<geographicCode> child element" do
|
250
|
+
it "should be a NodeSet" do
|
251
|
+
@geo_code_subject.geographicCode.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
252
|
+
end
|
253
|
+
it "cartographics NodeSet should have as many Nodes as there are <geographicCode> elements in the xml" do
|
254
|
+
@geo_code_subject.geographicCode.size.should == 1
|
255
|
+
end
|
256
|
+
it "text should get element value" do
|
257
|
+
@geo_code_subject.geographicCode.map { |n| n.text }.should == ['f------']
|
258
|
+
end
|
259
|
+
it "should recognize authority attributes" do
|
260
|
+
Mods::AUTHORITY_ATTRIBS.each { |a|
|
261
|
+
@mods_rec.from_str("<mods><subject><geographicCode #{a}='attr_val'>f------</geographicCode></subject></mods>")
|
262
|
+
@mods_rec.subject.geographicCode.send(a.to_sym).should == ['attr_val']
|
263
|
+
}
|
264
|
+
end
|
265
|
+
it "should recognize the sanctioned authorities" do
|
266
|
+
Mods::Subject::GEO_CODE_AUTHORITIES.each { |a|
|
267
|
+
@mods_rec.from_str("<mods><subject><geographicCode authority='#{a}'>f------</geographicCode></subject></mods>")
|
268
|
+
@mods_rec.subject.geographicCode.authority.should == [a]
|
269
|
+
}
|
270
|
+
end
|
271
|
+
it "should not recognize unsanctioned authorities?" do
|
272
|
+
@mods_rec.from_str("<mods><subject><geographicCode authority='fake'>f------</geographicCode></subject></mods>")
|
273
|
+
pending "to be implemented"
|
274
|
+
expect { @mods_rec.subject.geographicCode.authority }.to raise_error(/no idea/)
|
275
|
+
end
|
276
|
+
end # <geographicCode>
|
277
|
+
|
278
|
+
context "<titleInfo> child element" do
|
279
|
+
before(:all) do
|
280
|
+
@title_info = @mods_rec.from_str('<mods><subject>
|
281
|
+
<titleInfo>
|
282
|
+
<nonSort>The</nonSort>
|
283
|
+
<title>Olympics</title>
|
284
|
+
<subTitle>a history</subTitle>
|
285
|
+
</titleInfo>
|
286
|
+
</subject></mods>').subject.titleInfo
|
287
|
+
end
|
288
|
+
it "should understand all attributes allowed on a <titleInfo> element" do
|
289
|
+
Mods::TitleInfo::ATTRIBUTES.each { |a|
|
290
|
+
ti = @mods_rec.from_str("<mods><subject><titleInfo #{a}='attr_val'>THE</titleInfo></subject></mods>").subject.titleInfo
|
291
|
+
if (a == 'type')
|
292
|
+
ti.type_at.should == ['attr_val']
|
293
|
+
else
|
294
|
+
ti.send(a.to_sym).should == ['attr_val']
|
295
|
+
end
|
296
|
+
}
|
297
|
+
end
|
298
|
+
it "should understand all immediate child elements allowed on a <titleInfo> element" do
|
299
|
+
Mods::TitleInfo::CHILD_ELEMENTS.each { |e|
|
300
|
+
@mods_rec.from_str("<mods><subject><titleInfo><#{e}>el_val</#{e}></titleInfo></subject></mods>").subject.titleInfo.send(e.to_sym).text.should == 'el_val'
|
301
|
+
}
|
302
|
+
@title_info.nonSort.map {|n| n.text}.should == ["The"]
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should recognize authority attribute on the <titleInfo> element" do
|
306
|
+
@mods_rec.from_str('<mods><subject>
|
307
|
+
<titleInfo type="uniform" authority="naf">
|
308
|
+
<title>Missale Carnotense</title>
|
309
|
+
</titleInfo></subject></mods>').subject.titleInfo.authority.should == ["naf"]
|
310
|
+
end
|
311
|
+
end # <titleInfo>
|
312
|
+
|
313
|
+
context "<name> child element" do
|
314
|
+
it "should understand all attributes allowed on a <name> element" do
|
315
|
+
Mods::Name::ATTRIBUTES.each { |a|
|
316
|
+
name = @mods_rec.from_str("<mods><subject><name #{a}='attr_val'>Obadiah</name></subject></mods>").subject.name_
|
317
|
+
if (a == 'type')
|
318
|
+
name.type_at.should == ['attr_val']
|
319
|
+
else
|
320
|
+
name.send(a.to_sym).should == ['attr_val']
|
321
|
+
end
|
322
|
+
}
|
323
|
+
end
|
324
|
+
it "should understand all immediate child elements allowed on a <name> element" do
|
325
|
+
Mods::Name::CHILD_ELEMENTS.each { |e|
|
326
|
+
name = @mods_rec.from_str("<mods><subject><name><#{e}>el_val</#{e}></name></subject></mods>").subject.name_
|
327
|
+
if (e == 'description')
|
328
|
+
name.description_el.text.should == 'el_val'
|
329
|
+
elsif (e != 'role')
|
330
|
+
name.send(e.to_sym).text.should == 'el_val'
|
331
|
+
end
|
332
|
+
}
|
333
|
+
end
|
334
|
+
it "should recognize authority attribute on the <name> element" do
|
335
|
+
@mods_rec.from_str('<mods><subject>
|
336
|
+
<name type="personal" authority="lcsh">
|
337
|
+
<namePart>Nahl, Charles Christian</namePart>
|
338
|
+
<namePart type="date">1818-1878</namePart>
|
339
|
+
</name></mods>').subject.name_.authority.should == ["lcsh"]
|
340
|
+
end
|
341
|
+
end # <name>
|
342
|
+
|
343
|
+
context "<hiearchicalGeographic> child element" do
|
344
|
+
it "should recognize authority attributes" do
|
345
|
+
Mods::AUTHORITY_ATTRIBS.each { |a|
|
346
|
+
@mods_rec.from_str("<mods><subject><hierarchicalGeographic #{a}='attr_val'><country>Albania</country></hierarchicalGeographic></subject></mods>")
|
347
|
+
@mods_rec.subject.hierarchicalGeographic.send(a.to_sym).should == ['attr_val']
|
348
|
+
}
|
349
|
+
end
|
350
|
+
it "should recognize allowed child elements" do
|
351
|
+
Mods::Subject::HIER_GEO_CHILD_ELEMENTS.each { |e|
|
352
|
+
@mods_rec.from_str("<mods><subject><hierarchicalGeographic><#{e}>el_val</#{e}></hierarchicalGeographic></subject></mods>")
|
353
|
+
@mods_rec.subject.hierarchicalGeographic.send(e.to_sym).text.should == 'el_val'
|
354
|
+
}
|
355
|
+
Mods::Subject::HIER_GEO_CHILD_ELEMENTS.size.should == 12
|
356
|
+
end
|
357
|
+
end # <hierarchicalGeographic>
|
358
|
+
|
359
|
+
context "<cartographics> child element" do
|
360
|
+
before(:all) do
|
361
|
+
@carto_scale = @mods_rec.from_str('<mods><subject>
|
362
|
+
<cartographics>
|
363
|
+
<scale>[ca.1:90,000,000], [173</scale>
|
364
|
+
</cartographics>
|
365
|
+
</subject></mods>').subject.cartographics
|
366
|
+
@carto_empties = @mods_rec.from_str('<mods><subject authority="">
|
367
|
+
<cartographics>
|
368
|
+
<scale/>
|
369
|
+
<coordinates>W1730000 W0100000 N840000 N071000</coordinates>
|
370
|
+
<projection/>
|
371
|
+
</cartographics>
|
372
|
+
</subject></mods>').subject.cartographics
|
373
|
+
@multi_carto = @mods_rec.from_str('<mods><subject>
|
374
|
+
<cartographics>
|
375
|
+
<coordinates>W0180000 E0510000 N370000 S350000</coordinates>
|
376
|
+
</cartographics>
|
377
|
+
</subject><subject>
|
378
|
+
<cartographics>
|
379
|
+
<scale>Scale [ca. 1:50,000,000]</scale>
|
380
|
+
</cartographics>
|
381
|
+
<cartographics>
|
382
|
+
<coordinates>(W18°--E51°/N37°--S35°).</coordinates>
|
383
|
+
</cartographics>
|
384
|
+
</subject></mods>').subject.cartographics
|
385
|
+
end
|
386
|
+
it "should be a NodeSet" do
|
387
|
+
@carto_scale.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
388
|
+
@carto_empties.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
389
|
+
@multi_carto.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
390
|
+
end
|
391
|
+
it "cartographics NodeSet should have as many Nodes as there are <cartographics> elements in the xml" do
|
392
|
+
@carto_scale.size.should == 1
|
393
|
+
@carto_empties.size.should == 1
|
394
|
+
@multi_carto.size.should == 3
|
395
|
+
end
|
396
|
+
it "should recognize allowed child elements" do
|
397
|
+
Mods::Subject::CARTOGRAPHICS_CHILD_ELEMENTS.each { |e|
|
398
|
+
@mods_rec.from_str("<mods><subject><cartographics><#{e}>el_val</#{e}></cartographics></subject></mods>")
|
399
|
+
@mods_rec.subject.cartographics.send(e.to_sym).text.should == 'el_val'
|
400
|
+
}
|
401
|
+
Mods::Subject::CARTOGRAPHICS_CHILD_ELEMENTS.size.should == 3
|
402
|
+
end
|
403
|
+
it "should get the number of populated <coordinates> elements for coordinates term" do
|
404
|
+
@multi_carto.coordinates.size == 2
|
405
|
+
end
|
406
|
+
it "should be able to get the value of populated elements" do
|
407
|
+
@carto_scale.scale.map { |n| n.text }.should == ['[ca.1:90,000,000], [173']
|
408
|
+
@carto_empties.coordinates.map { |n| n.text }.should == ['W1730000 W0100000 N840000 N071000']
|
409
|
+
end
|
410
|
+
it "should get the empty string for empty elements?" do
|
411
|
+
@carto_empties.projection.map { |n| n.text }.should == ['']
|
412
|
+
end
|
413
|
+
end # <cartographics>
|
414
|
+
|
415
|
+
context "<occupation> child element" do
|
416
|
+
before(:all) do
|
417
|
+
@occupation = @mods_rec.from_str('<mods><subject><occupation>Migrant laborers</occupation></mods>').subject.occupation
|
418
|
+
end
|
419
|
+
it "should be a NodeSet" do
|
420
|
+
@occupation.should be_an_instance_of(Nokogiri::XML::NodeSet)
|
421
|
+
end
|
422
|
+
it "occupation NodeSet should have as many Nodes as there are <occupation> elements in the xml" do
|
423
|
+
@occupation.size.should == 1
|
424
|
+
end
|
425
|
+
it "text should get element value" do
|
426
|
+
@occupation.map { |n| n.text }.should == ['Migrant laborers']
|
427
|
+
end
|
428
|
+
it "should recognize authority attributes" do
|
429
|
+
Mods::AUTHORITY_ATTRIBS.each { |a|
|
430
|
+
@mods_rec.from_str("<mods><subject><occupation #{a}='attr_val'>Flunkie</occupation></subject></mods>")
|
431
|
+
@mods_rec.subject.occupation.send(a.to_sym).should == ['attr_val']
|
432
|
+
}
|
433
|
+
end
|
434
|
+
|
435
|
+
end # <occupation>
|
436
|
+
|
437
|
+
|
438
|
+
end # basic subject terminology
|
439
|
+
|
440
|
+
end
|
data/spec/title_spec.rb
CHANGED
@@ -9,12 +9,12 @@ describe "Mods <titleInfo> element" do
|
|
9
9
|
it "should recognize type attribute on titleInfo element" do
|
10
10
|
Mods::TitleInfo::TYPES.each { |t|
|
11
11
|
@mods_rec.from_str("<mods><titleInfo type='#{t}'>hi</titleInfo></mods>")
|
12
|
-
@mods_rec.title_info.type_at.
|
12
|
+
@mods_rec.title_info.type_at.should == [t]
|
13
13
|
}
|
14
14
|
end
|
15
15
|
|
16
16
|
it "should recognize subelements" do
|
17
|
-
Mods::TitleInfo::
|
17
|
+
Mods::TitleInfo::CHILD_ELEMENTS.each { |e|
|
18
18
|
@mods_rec.from_str("<mods><titleInfo><#{e}>oofda</#{e}></titleInfo></mods>")
|
19
19
|
@mods_rec.title_info.send(e).text.should == 'oofda'
|
20
20
|
}
|
@@ -29,4 +29,11 @@ describe "Mods Top Level Elements that do not have Child Elements" do
|
|
29
29
|
pending "need to implement ruby style version of (element/attribute) method names"
|
30
30
|
end
|
31
31
|
|
32
|
+
it "<genre> element should recognize authority attributes" do
|
33
|
+
pending "to be implemented"
|
34
|
+
Mods::AUTHORITY_ATTRIBS.each { |a|
|
35
|
+
@mods_rec.from_str("<mods><genre #{a}='attr_val'>Graphic Novels</genre></mods>").genre.send(a.to_sym).should == 'attr_val'
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
32
39
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mods
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-11-
|
13
|
+
date: 2012-11-09 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: nokogiri
|
@@ -182,6 +182,7 @@ files:
|
|
182
182
|
- lib/mods/nom_terminology.rb
|
183
183
|
- lib/mods/reader.rb
|
184
184
|
- lib/mods/record.rb
|
185
|
+
- lib/mods/subject.rb
|
185
186
|
- lib/mods/title_info.rb
|
186
187
|
- lib/mods/version.rb
|
187
188
|
- mods.gemspec
|
@@ -192,6 +193,7 @@ files:
|
|
192
193
|
- spec/physical_description_spec.rb
|
193
194
|
- spec/reader_spec.rb
|
194
195
|
- spec/spec_helper.rb
|
196
|
+
- spec/subject_spec.rb
|
195
197
|
- spec/title_spec.rb
|
196
198
|
- spec/top_level_elmnts_simple_spec.rb
|
197
199
|
homepage: https://github.com/sul-dlss/mods
|
@@ -208,7 +210,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
208
210
|
version: '0'
|
209
211
|
segments:
|
210
212
|
- 0
|
211
|
-
hash:
|
213
|
+
hash: -2903168770934676746
|
212
214
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
213
215
|
none: false
|
214
216
|
requirements:
|
@@ -217,7 +219,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
217
219
|
version: '0'
|
218
220
|
segments:
|
219
221
|
- 0
|
220
|
-
hash:
|
222
|
+
hash: -2903168770934676746
|
221
223
|
requirements: []
|
222
224
|
rubyforge_project:
|
223
225
|
rubygems_version: 1.8.24
|
@@ -232,6 +234,7 @@ test_files:
|
|
232
234
|
- spec/physical_description_spec.rb
|
233
235
|
- spec/reader_spec.rb
|
234
236
|
- spec/spec_helper.rb
|
237
|
+
- spec/subject_spec.rb
|
235
238
|
- spec/title_spec.rb
|
236
239
|
- spec/top_level_elmnts_simple_spec.rb
|
237
240
|
has_rdoc:
|