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.
Files changed (37) hide show
  1. data/lib/mods_display.rb +7 -1
  2. data/lib/mods_display/configuration.rb +7 -3
  3. data/lib/mods_display/configuration/access_condition.rb +17 -0
  4. data/lib/mods_display/configuration/format.rb +5 -0
  5. data/lib/mods_display/configuration/genre.rb +5 -0
  6. data/lib/mods_display/configuration/imprint.rb +8 -0
  7. data/lib/mods_display/controller_extension.rb +1 -1
  8. data/lib/mods_display/country_codes.rb +385 -0
  9. data/lib/mods_display/fields/access_condition.rb +73 -0
  10. data/lib/mods_display/fields/description.rb +1 -3
  11. data/lib/mods_display/fields/format.rb +23 -16
  12. data/lib/mods_display/fields/genre.rb +7 -1
  13. data/lib/mods_display/fields/identifier.rb +1 -0
  14. data/lib/mods_display/fields/imprint.rb +55 -6
  15. data/lib/mods_display/fields/location.rb +25 -3
  16. data/lib/mods_display/fields/name.rb +82 -13
  17. data/lib/mods_display/fields/related_item.rb +73 -14
  18. data/lib/mods_display/fields/resource_type.rb +7 -0
  19. data/lib/mods_display/html.rb +15 -9
  20. data/lib/mods_display/model_extension.rb +1 -0
  21. data/lib/mods_display/relator_codes.rb +268 -0
  22. data/lib/mods_display/version.rb +1 -1
  23. data/spec/configuration/access_condition_spec.rb +10 -0
  24. data/spec/fields/access_condition_spec.rb +91 -0
  25. data/spec/fields/description_spec.rb +9 -9
  26. data/spec/fields/format_spec.rb +10 -14
  27. data/spec/fields/genre_spec.rb +9 -1
  28. data/spec/fields/imprint_spec.rb +63 -2
  29. data/spec/fields/location_spec.rb +21 -2
  30. data/spec/fields/name_spec.rb +30 -0
  31. data/spec/fields/related_item_spec.rb +13 -0
  32. data/spec/fields/resource_type_spec.rb +6 -0
  33. data/spec/fixtures/imprint_fixtures.rb +36 -2
  34. data/spec/integration/configuration_spec.rb +14 -2
  35. metadata +15 -7
  36. data/lib/mods_display/fields/related_location.rb +0 -16
  37. 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, "&copy;").gsub(/\(c\)/i, "&copy;")
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
@@ -20,9 +20,7 @@ class ModsDisplay::Description < ModsDisplay::Field
20
20
  end
21
21
 
22
22
  def labels
23
- {:form => "Form",
24
- :extent => "Extent",
25
- :digitalOrigin => "Digital origin",
23
+ {:digitalOrigin => "Digital origin",
26
24
  :note => "Note"
27
25
  }
28
26
  end
@@ -1,29 +1,36 @@
1
1
  class ModsDisplay::Format < ModsDisplay::Field
2
2
 
3
3
  def fields
4
- return [] if @values.text.strip.empty?
5
- return_fields = @values.map do |value|
6
- ModsDisplay::Values.new(:label => displayLabel(value) || "Format", :values => [displayForm(value) || value.text])
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
- def to_html
12
- return nil if @config.ignore?
13
- output = ""
14
- fields.each do |field|
15
- output << "<dt#{label_class} title='#{field.label}'>#{field.label}:</dt>"
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.place.placeTerm.select do |term|
164
- !term.attributes["type"] or
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
- term.attributes["type"].value != "code"
167
- end.compact
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 displayLabel(element)
6
- super(element) || location_label(element) || "Location"
25
+ def location_field_keys
26
+ [:physicalLocation, :url, :shelfLocation, :holdingSimple, :holdingExternal]
7
27
  end
8
28
 
9
29
  def location_label(element)
10
- if element.attributes["type"].respond_to?(:value) && location_labels.has_key?(element.attributes["type"].value)
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 = nil
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
- else
16
- name_parts = value.namePart.map do |name_part|
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.typeOfResource.length > 0 and
6
- value.typeOfResource.attributes.length > 0 and
7
- value.typeOfResource.attributes.first.has_key?("collection") and
8
- value.typeOfResource.attributes.first["collection"].value == "yes")
9
- if value.titleInfo.length > 0
10
- title = value.titleInfo.text.strip
11
- return_text = title
12
- location = nil
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