mods_display 0.1.3 → 0.1.4
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/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
|