mods_display 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/mods_display.rb +7 -1
- data/lib/mods_display/configuration.rb +7 -3
- data/lib/mods_display/configuration/access_condition.rb +17 -0
- data/lib/mods_display/configuration/format.rb +5 -0
- data/lib/mods_display/configuration/genre.rb +5 -0
- data/lib/mods_display/configuration/imprint.rb +8 -0
- data/lib/mods_display/controller_extension.rb +1 -1
- data/lib/mods_display/country_codes.rb +385 -0
- data/lib/mods_display/fields/access_condition.rb +73 -0
- data/lib/mods_display/fields/description.rb +1 -3
- data/lib/mods_display/fields/format.rb +23 -16
- data/lib/mods_display/fields/genre.rb +7 -1
- data/lib/mods_display/fields/identifier.rb +1 -0
- data/lib/mods_display/fields/imprint.rb +55 -6
- data/lib/mods_display/fields/location.rb +25 -3
- data/lib/mods_display/fields/name.rb +82 -13
- data/lib/mods_display/fields/related_item.rb +73 -14
- data/lib/mods_display/fields/resource_type.rb +7 -0
- data/lib/mods_display/html.rb +15 -9
- data/lib/mods_display/model_extension.rb +1 -0
- data/lib/mods_display/relator_codes.rb +268 -0
- data/lib/mods_display/version.rb +1 -1
- data/spec/configuration/access_condition_spec.rb +10 -0
- data/spec/fields/access_condition_spec.rb +91 -0
- data/spec/fields/description_spec.rb +9 -9
- data/spec/fields/format_spec.rb +10 -14
- data/spec/fields/genre_spec.rb +9 -1
- data/spec/fields/imprint_spec.rb +63 -2
- data/spec/fields/location_spec.rb +21 -2
- data/spec/fields/name_spec.rb +30 -0
- data/spec/fields/related_item_spec.rb +13 -0
- data/spec/fields/resource_type_spec.rb +6 -0
- data/spec/fixtures/imprint_fixtures.rb +36 -2
- data/spec/integration/configuration_spec.rb +14 -2
- metadata +15 -7
- data/lib/mods_display/fields/related_location.rb +0 -16
- data/spec/fields/related_location_spec.rb +0 -35
@@ -0,0 +1,73 @@
|
|
1
|
+
class ModsDisplay::AccessCondition < ModsDisplay::Field
|
2
|
+
|
3
|
+
def fields
|
4
|
+
return_fields = @values.map do |value|
|
5
|
+
ModsDisplay::Values.new(:label => displayLabel(value) || access_label(value), :values => [process_access_statement(value)])
|
6
|
+
end
|
7
|
+
collapse_fields(return_fields)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def process_access_statement(element)
|
13
|
+
case normalize_type(element)
|
14
|
+
when "copyright"
|
15
|
+
copyright_statement(element)
|
16
|
+
when "license"
|
17
|
+
license_statement(element)
|
18
|
+
else
|
19
|
+
element.text
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def copyright_statement(element)
|
24
|
+
element.text.gsub(/\(c\) copyright/i, "©").gsub(/\(c\)/i, "©")
|
25
|
+
end
|
26
|
+
|
27
|
+
def license_statement(element)
|
28
|
+
element.text[/^(.*) (.*):(.*)$/]
|
29
|
+
output = "<div class='#{[$1,$2].join('-').downcase}'>"
|
30
|
+
if license_link($1, $2)
|
31
|
+
output << "<a href='#{license_link($1, $2)}'>#{$3.strip}</a>"
|
32
|
+
else
|
33
|
+
output << $3.strip
|
34
|
+
end
|
35
|
+
output << "</div>"
|
36
|
+
end
|
37
|
+
|
38
|
+
def license_code_urls
|
39
|
+
{"cc" => "http://creativecommons.org/licenses/",
|
40
|
+
"odc" => "http://opendatacommons.org/licenses/"}
|
41
|
+
end
|
42
|
+
|
43
|
+
def license_link(code, type)
|
44
|
+
code = code.downcase
|
45
|
+
if license_code_urls.has_key?(code)
|
46
|
+
"#{license_code_urls[code]}#{type.downcase}#{"/#{@config.cc_license_version}/" if code == 'cc'}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def access_label(element)
|
51
|
+
type = normalize_type(element)
|
52
|
+
if access_labels.has_key?(type)
|
53
|
+
return access_labels[type]
|
54
|
+
end
|
55
|
+
"Access condition"
|
56
|
+
end
|
57
|
+
|
58
|
+
def normalize_type(element)
|
59
|
+
type = element.attributes["type"]
|
60
|
+
if type.respond_to?(:value)
|
61
|
+
return type.value.strip.gsub(/\s*/, "").downcase
|
62
|
+
end
|
63
|
+
""
|
64
|
+
end
|
65
|
+
|
66
|
+
def access_labels
|
67
|
+
{"useandreproduction" => "Use and reproduction",
|
68
|
+
"restrictiononaccess" => "Restriction on access",
|
69
|
+
"copyright" => "Copyright",
|
70
|
+
"license" => "License"
|
71
|
+
}
|
72
|
+
end
|
73
|
+
end
|
@@ -1,29 +1,36 @@
|
|
1
1
|
class ModsDisplay::Format < ModsDisplay::Field
|
2
2
|
|
3
3
|
def fields
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
return_fields = []
|
5
|
+
# if @values.respond_to?(:format) and
|
6
|
+
# !@values.format.nil? and
|
7
|
+
# !@values.format.empty?
|
8
|
+
# return_fields << ModsDisplay::Values.new(:label => "Format",
|
9
|
+
# :values => [decorate_formats(@values.format).join(", ")])
|
10
|
+
# end
|
11
|
+
unless @values.physical_description.nil?
|
12
|
+
@values.physical_description.each do |description|
|
13
|
+
unless description.form.nil? or description.form.empty?
|
14
|
+
return_fields << ModsDisplay::Values.new(:label => displayLabel(description) || "Format",
|
15
|
+
:values => [description.form.map{|f| f.text.strip }.uniq.join(", ")])
|
16
|
+
end
|
17
|
+
unless description.extent.nil? or description.extent.empty?
|
18
|
+
return_fields << ModsDisplay::Values.new(:label => displayLabel(description) || "Format",
|
19
|
+
:values => [description.extent.map{|e| e.text }.join(", ")])
|
20
|
+
end
|
21
|
+
end
|
7
22
|
end
|
8
23
|
collapse_fields(return_fields)
|
9
24
|
end
|
10
25
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
output << "<dd#{value_class}>"
|
17
|
-
field.values.map do |val|
|
18
|
-
output << "<span class='#{self.class.format_class(val)}'>#{val}</span>"
|
19
|
-
end.join(@config.delimiter)
|
20
|
-
output << "</dd>"
|
26
|
+
private
|
27
|
+
|
28
|
+
def decorate_formats(formats)
|
29
|
+
formats.map do |format|
|
30
|
+
"<span data-mods-display-format='#{self.class.format_class(format)}'>#{format}</span>"
|
21
31
|
end
|
22
|
-
output
|
23
32
|
end
|
24
33
|
|
25
|
-
private
|
26
|
-
|
27
34
|
def self.format_class(format)
|
28
35
|
return format if format.nil?
|
29
36
|
format.strip.downcase.gsub(/\/|\\|\s+/, "_")
|
@@ -1,8 +1,14 @@
|
|
1
1
|
class ModsDisplay::Genre < ModsDisplay::Field
|
2
2
|
|
3
|
+
def fields
|
4
|
+
return_fields = @values.map do |value|
|
5
|
+
ModsDisplay::Values.new(:label => displayLabel(value) || label, :values => [value.text.strip.capitalize].flatten)
|
6
|
+
end
|
7
|
+
collapse_fields(return_fields)
|
8
|
+
end
|
3
9
|
|
4
10
|
private
|
5
|
-
|
11
|
+
|
6
12
|
def displayLabel(element)
|
7
13
|
super(element) || "Genre"
|
8
14
|
end
|
@@ -27,6 +27,7 @@ class ModsDisplay::Identifier < ModsDisplay::Field
|
|
27
27
|
"ismn" => "ISMN",
|
28
28
|
"issue number" => "Issue number",
|
29
29
|
"lccn" => "LCCN",
|
30
|
+
"oclc" => "OCLC",
|
30
31
|
"matrix number" => "Matrix number",
|
31
32
|
"music publisher" => "Music publisher",
|
32
33
|
"music plate" => "Music plate",
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class ModsDisplay::Imprint < ModsDisplay::Field
|
2
|
-
|
2
|
+
include ModsDisplay::CountryCodes
|
3
3
|
def fields
|
4
4
|
return_fields = []
|
5
5
|
@values.each do |value|
|
@@ -58,7 +58,21 @@ class ModsDisplay::Imprint < ModsDisplay::Field
|
|
58
58
|
end.compact
|
59
59
|
end
|
60
60
|
def parse_dates(date_field)
|
61
|
-
apply_date_qualifier_decoration dedup_dates join_date_ranges date_field
|
61
|
+
apply_date_qualifier_decoration dedup_dates join_date_ranges process_encoded_dates ignore_bad_dates date_field
|
62
|
+
end
|
63
|
+
def ignore_bad_dates(date_fields)
|
64
|
+
date_fields.select do |date_field|
|
65
|
+
date_field.text.strip != "9999"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
def process_encoded_dates(date_fields)
|
69
|
+
date_fields.map do |date_field|
|
70
|
+
if date_is_w3cdtf?(date_field)
|
71
|
+
process_w3cdtf_date(date_field)
|
72
|
+
else
|
73
|
+
date_field
|
74
|
+
end
|
75
|
+
end
|
62
76
|
end
|
63
77
|
def join_date_ranges(date_fields)
|
64
78
|
if dates_are_range?(date_fields)
|
@@ -135,6 +149,22 @@ class ModsDisplay::Imprint < ModsDisplay::Field
|
|
135
149
|
attributes.include?("start") and
|
136
150
|
attributes.include?("end")
|
137
151
|
end
|
152
|
+
def date_is_w3cdtf?(date_field)
|
153
|
+
date_field.attributes["encoding"] and
|
154
|
+
date_field.attributes["encoding"].respond_to?(:value) and
|
155
|
+
date_field.attributes["encoding"].value.downcase == "w3cdtf"
|
156
|
+
end
|
157
|
+
def process_w3cdtf_date(date_field)
|
158
|
+
date_field = date_field.clone
|
159
|
+
date_field.content = if date_field.text.strip =~ /^\d{4}-\d{2}-\d{2}$/
|
160
|
+
Date.parse(date_field.text).strftime(@config.full_date_format)
|
161
|
+
elsif date_field.text.strip =~ /^\d{4}-\d{2}$/
|
162
|
+
Date.parse("#{date_field.text}-01").strftime(@config.short_date_format)
|
163
|
+
else
|
164
|
+
date_field.content
|
165
|
+
end
|
166
|
+
date_field
|
167
|
+
end
|
138
168
|
def dedup_dates(date_fields)
|
139
169
|
date_text = date_fields.map{|d| normalize_date(d.text) }
|
140
170
|
if date_text != date_text.uniq
|
@@ -160,11 +190,30 @@ class ModsDisplay::Imprint < ModsDisplay::Field
|
|
160
190
|
def place_terms(element)
|
161
191
|
return [] unless element.respond_to?(:place) and
|
162
192
|
element.place.respond_to?(:placeTerm)
|
163
|
-
element
|
164
|
-
|
193
|
+
if unencoded_place_terms?(element)
|
194
|
+
element.place.placeTerm.select do |term|
|
195
|
+
!term.attributes["type"].respond_to?(:value) or
|
196
|
+
term.attributes["type"].value == "text"
|
197
|
+
end.compact
|
198
|
+
else
|
199
|
+
element.place.placeTerm.map do |term|
|
200
|
+
if term.attributes["type"].respond_to?(:value) and
|
201
|
+
term.attributes["type"].value == "code" and
|
202
|
+
term.attributes["authority"].respond_to?(:value) and
|
203
|
+
term.attributes["authority"].value == "marccountry" and
|
204
|
+
country_codes.include?(term.text.strip)
|
205
|
+
term = term.clone
|
206
|
+
term.content = country_codes[term.text.strip]
|
207
|
+
term
|
208
|
+
end
|
209
|
+
end.compact
|
210
|
+
end
|
211
|
+
end
|
212
|
+
def unencoded_place_terms?(element)
|
213
|
+
element.place.placeTerm.any? do |term|
|
165
214
|
!term.attributes["type"].respond_to?(:value) or
|
166
|
-
|
167
|
-
end
|
215
|
+
term.attributes["type"].value == "text"
|
216
|
+
end
|
168
217
|
end
|
169
218
|
def imprint_display_form(element)
|
170
219
|
display_form = element.children.find do |child|
|
@@ -1,13 +1,35 @@
|
|
1
1
|
class ModsDisplay::Location < ModsDisplay::Field
|
2
2
|
|
3
|
+
def fields
|
4
|
+
return_fields = []
|
5
|
+
@values.each do |location|
|
6
|
+
location.children.each do |child|
|
7
|
+
if location_field_keys.include? child.name.to_sym
|
8
|
+
if child.name.to_sym == :url
|
9
|
+
loc_label = displayLabel(location) || "Location"
|
10
|
+
value = "<a href='#{child.text}'>#{displayLabel(child) || child.text}</a>"
|
11
|
+
else
|
12
|
+
loc_label = location_label(child) || displayLabel(location) || "Location"
|
13
|
+
value = child.text
|
14
|
+
end
|
15
|
+
return_fields << ModsDisplay::Values.new(:label => loc_label || displayLabel(location) || "Location",
|
16
|
+
:values => [value])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
collapse_fields(return_fields)
|
21
|
+
end
|
22
|
+
|
3
23
|
private
|
4
24
|
|
5
|
-
def
|
6
|
-
|
25
|
+
def location_field_keys
|
26
|
+
[:physicalLocation, :url, :shelfLocation, :holdingSimple, :holdingExternal]
|
7
27
|
end
|
8
28
|
|
9
29
|
def location_label(element)
|
10
|
-
if
|
30
|
+
if displayLabel(element)
|
31
|
+
displayLabel(element)
|
32
|
+
elsif element.attributes["type"].respond_to?(:value) && location_labels.has_key?(element.attributes["type"].value)
|
11
33
|
location_labels[element.attributes["type"].value]
|
12
34
|
end
|
13
35
|
end
|
@@ -1,22 +1,13 @@
|
|
1
1
|
class ModsDisplay::Name < ModsDisplay::Field
|
2
|
-
|
2
|
+
include ModsDisplay::RelatorCodes
|
3
3
|
def fields
|
4
4
|
return_fields = @values.map do |value|
|
5
|
-
role =
|
5
|
+
role = process_role(value)
|
6
6
|
person = nil
|
7
|
-
if value.role.length > 0 and value.role.roleTerm.length > 0
|
8
|
-
role = value.role.roleTerm.find do |term|
|
9
|
-
term.attributes["type"].respond_to?(:value) and
|
10
|
-
term.attributes["type"].value == "text"
|
11
|
-
end
|
12
|
-
end
|
13
7
|
if value.displayForm.length > 0
|
14
8
|
person = ModsDisplay::Name::Person.new(:name => value.displayForm.text, :role => role)
|
15
|
-
|
16
|
-
|
17
|
-
name_part.text
|
18
|
-
end.join(", ")
|
19
|
-
person = ModsDisplay::Name::Person.new(:name => name_parts, :role => role) unless name_parts.empty?
|
9
|
+
elsif !name_parts(value).empty?
|
10
|
+
person = ModsDisplay::Name::Person.new(:name => name_parts(value), :role => role)
|
20
11
|
end
|
21
12
|
ModsDisplay::Values.new(:label => displayLabel(value) || name_label(value), :values => [person]) if person
|
22
13
|
end.compact
|
@@ -64,6 +55,84 @@ class ModsDisplay::Name < ModsDisplay::Field
|
|
64
55
|
end
|
65
56
|
end
|
66
57
|
|
58
|
+
def name_parts(element)
|
59
|
+
output = ""
|
60
|
+
output << [unqualified_name_parts(element),
|
61
|
+
qualified_name_parts(element, "family"),
|
62
|
+
qualified_name_parts(element, "given")].flatten.compact.join(", ")
|
63
|
+
terms = qualified_name_parts(element, "termsOfAddress")
|
64
|
+
unless terms.empty?
|
65
|
+
term_delimiter = ", "
|
66
|
+
if name_part_begins_with_roman_numeral?(terms.first)
|
67
|
+
term_delimiter = " "
|
68
|
+
end
|
69
|
+
output = [output, terms.join(", ")].flatten.compact.join(term_delimiter)
|
70
|
+
end
|
71
|
+
dates = qualified_name_parts(element, "date")
|
72
|
+
unless dates.empty?
|
73
|
+
output = [output, qualified_name_parts(element, "date")].flatten.compact.join(", ")
|
74
|
+
end
|
75
|
+
output
|
76
|
+
end
|
77
|
+
|
78
|
+
def unqualified_name_parts(element)
|
79
|
+
element.namePart.map do |part|
|
80
|
+
part.text unless part.attributes["type"]
|
81
|
+
end.compact
|
82
|
+
end
|
83
|
+
|
84
|
+
def qualified_name_parts(element, type)
|
85
|
+
element.namePart.map do |part|
|
86
|
+
if part.attributes["type"].respond_to?(:value) and
|
87
|
+
part.attributes["type"].value == type
|
88
|
+
part.text
|
89
|
+
end
|
90
|
+
end.compact
|
91
|
+
end
|
92
|
+
|
93
|
+
def name_part_begins_with_roman_numeral?(part)
|
94
|
+
first_part = part.split(/\s|,/).first.strip
|
95
|
+
first_part.chars.all? do |char|
|
96
|
+
["I", "X", "C", "L", "V"].include? char
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def process_role(element)
|
101
|
+
if element.role.length > 0 and element.role.roleTerm.length > 0
|
102
|
+
if unencoded_role_term?(element)
|
103
|
+
unencoded_role_term(element)
|
104
|
+
else
|
105
|
+
element.role.roleTerm.map do |term|
|
106
|
+
if term.attributes["type"].respond_to?(:value) and
|
107
|
+
term.attributes["type"].value == "code" and
|
108
|
+
term.attributes["authority"].respond_to?(:value) and
|
109
|
+
term.attributes["authority"].value == "marcrelator" and
|
110
|
+
relator_codes.include?(term.text.strip)
|
111
|
+
term = term.clone
|
112
|
+
term.content = relator_codes[term.text.strip]
|
113
|
+
term
|
114
|
+
end
|
115
|
+
end.compact.first
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def unencoded_role_term(element)
|
121
|
+
element.role.roleTerm.find do |term|
|
122
|
+
term.attributes["type"].respond_to?(:value) and
|
123
|
+
term.attributes["type"].value == "text"
|
124
|
+
end || element.role.roleTerm.find do |term|
|
125
|
+
!term.attributes["type"].respond_to?(:value)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def unencoded_role_term?(element)
|
130
|
+
element.role.roleTerm.any? do |term|
|
131
|
+
!term.attributes["type"].respond_to?(:value) or
|
132
|
+
term.attributes["type"].value == "text"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
67
136
|
def name_labels
|
68
137
|
{"personal" => "Author/Creator",
|
69
138
|
"corporate" => "Corporate author",
|
@@ -2,24 +2,83 @@ class ModsDisplay::RelatedItem < ModsDisplay::Field
|
|
2
2
|
|
3
3
|
def fields
|
4
4
|
return_fields = @values.map do |value|
|
5
|
-
unless (value
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
location = value.location.url.text if (value.location.length > 0 and
|
14
|
-
value.location.url.length > 0)
|
15
|
-
return_text = "<a href='#{location}'>#{title}</a>" if location and !title.empty?
|
16
|
-
unless return_text.empty?
|
17
|
-
ModsDisplay::Values.new(:label => displayLabel(value) || "Related item", :values => [return_text])
|
18
|
-
end
|
5
|
+
unless related_item_is_a_collection?(value)
|
6
|
+
case
|
7
|
+
when related_item_is_a_location?(value)
|
8
|
+
process_location value
|
9
|
+
when related_item_is_a_reference?(value)
|
10
|
+
process_reference value
|
11
|
+
else
|
12
|
+
process_related_item(value)
|
19
13
|
end
|
20
14
|
end
|
21
15
|
end.compact
|
22
16
|
collapse_fields(return_fields)
|
23
17
|
end
|
24
18
|
|
19
|
+
private
|
20
|
+
|
21
|
+
def process_location(item)
|
22
|
+
ModsDisplay::Values.new(:label => related_item_label(item), :values => [item.location.text.strip])
|
23
|
+
end
|
24
|
+
|
25
|
+
def process_reference(item)
|
26
|
+
ModsDisplay::Values.new(:label => related_item_label(item), :values => [reference_title(item)])
|
27
|
+
end
|
28
|
+
|
29
|
+
def process_related_item(item)
|
30
|
+
if item.titleInfo.length > 0
|
31
|
+
title = item.titleInfo.text.strip
|
32
|
+
return_text = title
|
33
|
+
location = nil
|
34
|
+
location = item.location.url.text if (item.location.length > 0 and
|
35
|
+
item.location.url.length > 0)
|
36
|
+
return_text = "<a href='#{location}'>#{title}</a>" if location and !title.empty?
|
37
|
+
unless return_text.empty?
|
38
|
+
ModsDisplay::Values.new(:label => related_item_label(item), :values => [return_text])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def reference_title(item)
|
44
|
+
[item.titleInfo,
|
45
|
+
item.originInfo.dateOther,
|
46
|
+
item.part.detail.number,
|
47
|
+
item.note].flatten.compact.map!(&:text).map!(&:strip).join(" ")
|
48
|
+
end
|
49
|
+
|
50
|
+
def related_item_is_a_collection?(item)
|
51
|
+
item.respond_to?(:titleInfo) and
|
52
|
+
item.respond_to?(:typeOfResource) and
|
53
|
+
item.typeOfResource.attributes.length > 0 and
|
54
|
+
item.typeOfResource.attributes.first.has_key?("collection") and
|
55
|
+
item.typeOfResource.attributes.first["collection"].value == "yes"
|
56
|
+
end
|
57
|
+
|
58
|
+
def related_item_is_a_location?(item)
|
59
|
+
!related_item_is_a_collection?(item) and
|
60
|
+
!related_item_is_a_reference?(item) and
|
61
|
+
item.location.length > 0 and
|
62
|
+
item.titleInfo.length < 1
|
63
|
+
end
|
64
|
+
|
65
|
+
def related_item_is_a_reference?(item)
|
66
|
+
!related_item_is_a_collection?(item) and
|
67
|
+
item.attributes["type"].respond_to?(:value) and
|
68
|
+
item.attributes["type"].value == "isReferencedBy"
|
69
|
+
end
|
70
|
+
|
71
|
+
def related_item_label(item)
|
72
|
+
if displayLabel(item)
|
73
|
+
return displayLabel(item)
|
74
|
+
else
|
75
|
+
case
|
76
|
+
when related_item_is_a_location?(item)
|
77
|
+
return "Location"
|
78
|
+
when related_item_is_a_reference?(item)
|
79
|
+
return "Referenced by"
|
80
|
+
end
|
81
|
+
"Related item"
|
82
|
+
end
|
83
|
+
end
|
25
84
|
end
|