mods_display 1.3.4 → 1.4.0
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -0
- data/lib/mods_display/fields/imprint.rb +3 -3
- data/lib/mods_display/fields/name.rb +6 -80
- data/lib/mods_display/fields/nested_related_item.rb +3 -3
- data/lib/mods_display/fields/related_item.rb +14 -28
- data/lib/mods_display/name_formatter.rb +72 -0
- data/lib/mods_display/related_item_concerns.rb +50 -15
- data/lib/mods_display/version.rb +1 -1
- data/lib/mods_display.rb +3 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd385f9d4aea6c14524378831877c327c6fdfd2664356e148b457af9c26a5623
|
4
|
+
data.tar.gz: b66857f71c766dc6edb03b8783d1d63486e94c63c8e9a71a0474f6b5a11d44cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b4760e8eee0c1eef22badaf5087b4095c4c88766c3b128bbaa1e841e2b1aa34294ced0be7199875b6aa57cdf1b3385dd5c11d624f4ce818afcc7fa4f1da25ab
|
7
|
+
data.tar.gz: 93c93c4249b55816c9716b1c632d0b4c5b5a2874365e33139fbbf6cd9421f01d3aa9800d347c72ae7837bcf98ef763650e8151a3cab547cecb287a72ff7a9ace
|
data/.rubocop.yml
CHANGED
@@ -64,12 +64,12 @@ module ModsDisplay
|
|
64
64
|
element.place.respond_to?(:placeTerm)
|
65
65
|
|
66
66
|
if unencoded_place_terms?(element)
|
67
|
-
element.place
|
67
|
+
element.xpath('mods:place/mods:placeTerm', mods: MODS_NS).select do |term|
|
68
68
|
!term.attributes['type'].respond_to?(:value) ||
|
69
69
|
term.attributes['type'].value == 'text'
|
70
70
|
end.compact
|
71
71
|
else
|
72
|
-
element.place
|
72
|
+
element.xpath('mods:place/mods:placeTerm', mods: MODS_NS).map do |term|
|
73
73
|
next unless term.attributes['type'].respond_to?(:value) &&
|
74
74
|
term.attributes['type'].value == 'code' &&
|
75
75
|
term.attributes['authority'].respond_to?(:value) &&
|
@@ -84,7 +84,7 @@ module ModsDisplay
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def unencoded_place_terms?(element)
|
87
|
-
element.place
|
87
|
+
element.xpath('mods:place/mods:placeTerm', mods: MODS_NS).any? do |term|
|
88
88
|
!term.attributes['type'].respond_to?(:value) ||
|
89
89
|
term.attributes['type'].value == 'text'
|
90
90
|
end
|
@@ -8,12 +8,8 @@ module ModsDisplay
|
|
8
8
|
# { role1 label => [ ModsDisplay:Name:Person, ModsDisplay:Name:Person, ...], role2 label => [ ModsDisplay:Name:Person, ModsDisplay:Name:Person, ...] }
|
9
9
|
def fields
|
10
10
|
return_fields = @values.map do |value|
|
11
|
-
|
12
|
-
person =
|
13
|
-
ModsDisplay::Name::Person.new(name: element_text(value.displayForm), name_identifiers: name_identifiers)
|
14
|
-
elsif !name_parts(value).empty?
|
15
|
-
ModsDisplay::Name::Person.new(name: name_parts(value), name_identifiers: name_identifiers)
|
16
|
-
end
|
11
|
+
name_parts = ModsDisplay::NameFormatter.format(value)
|
12
|
+
person = name_parts ? ModsDisplay::Name::Person.new(name: name_parts, name_identifiers: value.xpath('mods:nameIdentifier', mods: MODS_NS)) : nil
|
17
13
|
# The person may have multiple roles, so we have to divide them up into an array
|
18
14
|
role_labels(value).collect do |role_label|
|
19
15
|
ModsDisplay::Values.new(label: displayLabel(value) || role_label, values: [person]) if person
|
@@ -50,10 +46,10 @@ module ModsDisplay
|
|
50
46
|
|
51
47
|
def role_labels(element)
|
52
48
|
default_label = I18n.t('mods_display.associated_with')
|
53
|
-
return [default_label] unless element.role
|
49
|
+
return [default_label] unless element.xpath('mods:role/mods:roleTerm', mods: MODS_NS).present?
|
54
50
|
|
55
|
-
element.role.collect do |role|
|
56
|
-
codes, text = role.roleTerm.partition { |term| term['type'] == 'code' }
|
51
|
+
element.xpath('mods:role', mods: MODS_NS).collect do |role|
|
52
|
+
codes, text = role.xpath('mods:roleTerm', mods: MODS_NS).partition { |term| term['type'] == 'code' }
|
57
53
|
|
58
54
|
# prefer mappable role term codes
|
59
55
|
label = codes.map { |term| relator_codes[term.text.downcase] }.first
|
@@ -70,76 +66,6 @@ module ModsDisplay
|
|
70
66
|
element_text(element).capitalize.sub(/[.,:;]+$/, '')
|
71
67
|
end
|
72
68
|
|
73
|
-
def role?(element)
|
74
|
-
element.respond_to?(:role) && !element.role.empty?
|
75
|
-
end
|
76
|
-
|
77
|
-
def primary?(element)
|
78
|
-
element.attributes['usage'].respond_to?(:value) &&
|
79
|
-
element.attributes['usage'].value == 'primary'
|
80
|
-
end
|
81
|
-
|
82
|
-
def name_parts(element)
|
83
|
-
output = [unqualified_name_parts(element),
|
84
|
-
qualified_name_parts(element, 'family'),
|
85
|
-
qualified_name_parts(element, 'given')].flatten.compact.join(', ')
|
86
|
-
terms = qualified_name_parts(element, 'termsOfAddress')
|
87
|
-
unless terms.empty?
|
88
|
-
term_delimiter = ', '
|
89
|
-
term_delimiter = ' ' if name_part_begins_with_roman_numeral?(terms.first)
|
90
|
-
output = [output, terms.join(', ')].flatten.compact.join(term_delimiter)
|
91
|
-
end
|
92
|
-
dates = qualified_name_parts(element, 'date')
|
93
|
-
output = [output, qualified_name_parts(element, 'date')].flatten.compact.join(', ') unless dates.empty?
|
94
|
-
output
|
95
|
-
end
|
96
|
-
|
97
|
-
def unqualified_name_parts(element)
|
98
|
-
element.namePart.map do |part|
|
99
|
-
element_text(part) unless part.attributes['type']
|
100
|
-
end.compact
|
101
|
-
end
|
102
|
-
|
103
|
-
def qualified_name_parts(element, type)
|
104
|
-
element.namePart.map do |part|
|
105
|
-
if part.attributes['type'].respond_to?(:value) &&
|
106
|
-
part.attributes['type'].value == type
|
107
|
-
element_text(part)
|
108
|
-
end
|
109
|
-
end.compact
|
110
|
-
end
|
111
|
-
|
112
|
-
def name_part_begins_with_roman_numeral?(part)
|
113
|
-
first_part = part.split(/\s|,/).first.strip
|
114
|
-
first_part.chars.all? do |char|
|
115
|
-
%w[I X C L V].include? char
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def unencoded_role_term(element)
|
120
|
-
roles = element.role.map do |role|
|
121
|
-
role.roleTerm.find do |term|
|
122
|
-
term.attributes['type'].respond_to?(:value) &&
|
123
|
-
term.attributes['type'].value == 'text'
|
124
|
-
end
|
125
|
-
end.compact
|
126
|
-
if roles.empty?
|
127
|
-
roles = element.role.map do |role|
|
128
|
-
role.roleTerm.find do |term|
|
129
|
-
!term.attributes['type'].respond_to?(:value)
|
130
|
-
end
|
131
|
-
end.compact
|
132
|
-
end
|
133
|
-
roles.map { |t| element_text(t) }
|
134
|
-
end
|
135
|
-
|
136
|
-
def unencoded_role_term?(element)
|
137
|
-
element.role.roleTerm.any? do |term|
|
138
|
-
!term.attributes['type'].respond_to?(:value) ||
|
139
|
-
term.attributes['type'].value == 'text'
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
69
|
# Consolidate all names under label headings
|
144
70
|
def consolidate_under_labels(fields)
|
145
71
|
results = {}
|
@@ -194,7 +120,7 @@ module ModsDisplay
|
|
194
120
|
|
195
121
|
def orcid_identifier(name_identifiers)
|
196
122
|
orcid = name_identifiers.select do |name_identifier|
|
197
|
-
name_identifier.
|
123
|
+
name_identifier.get_attribute('type') == 'orcid'
|
198
124
|
end
|
199
125
|
orcid.first&.text
|
200
126
|
end
|
@@ -10,8 +10,8 @@ module ModsDisplay
|
|
10
10
|
|
11
11
|
def fields
|
12
12
|
@fields ||= begin
|
13
|
-
return_fields = @values.map do |value|
|
14
|
-
next if
|
13
|
+
return_fields = RelatedItemValue.for_values(@values).map do |value|
|
14
|
+
next if value.collection?
|
15
15
|
next unless render_nested_related_item?(value)
|
16
16
|
|
17
17
|
related_item_mods_object(value)
|
@@ -63,7 +63,7 @@ module ModsDisplay
|
|
63
63
|
|
64
64
|
def related_item_label(item)
|
65
65
|
return displayLabel(item) if displayLabel(item)
|
66
|
-
return I18n.t('mods_display.constituent') if
|
66
|
+
return I18n.t('mods_display.constituent') if item.constituent?
|
67
67
|
|
68
68
|
I18n.t('mods_display.host')
|
69
69
|
end
|
@@ -5,8 +5,8 @@ module ModsDisplay
|
|
5
5
|
include ModsDisplay::RelatedItemConcerns
|
6
6
|
|
7
7
|
def fields
|
8
|
-
return_fields = @values.map do |value|
|
9
|
-
next if
|
8
|
+
return_fields = RelatedItemValue.for_values(@values).map do |value|
|
9
|
+
next if value.collection?
|
10
10
|
next if render_nested_related_item?(value)
|
11
11
|
|
12
12
|
text = related_item_value(value)
|
@@ -25,15 +25,14 @@ module ModsDisplay
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def related_item_value(item)
|
28
|
-
if
|
29
|
-
element_text(item.
|
30
|
-
elsif
|
28
|
+
if item.location?
|
29
|
+
element_text(item.location_nodeset)
|
30
|
+
elsif item.reference?
|
31
31
|
reference_title(item)
|
32
|
-
elsif item.
|
33
|
-
title = element_text(item.
|
32
|
+
elsif item.titleInfo_nodeset.any?
|
33
|
+
title = element_text(item.titleInfo_nodeset)
|
34
34
|
location = nil
|
35
|
-
location = element_text(item.
|
36
|
-
item.location.url.length.positive?
|
35
|
+
location = element_text(item.location_url_nodeset) if item.location_url_nodeset.length.positive?
|
37
36
|
|
38
37
|
return if title.empty?
|
39
38
|
|
@@ -42,31 +41,18 @@ module ModsDisplay
|
|
42
41
|
else
|
43
42
|
title
|
44
43
|
end
|
45
|
-
elsif item.
|
46
|
-
citation = item.
|
44
|
+
elsif item.note_nodeset.any?
|
45
|
+
citation = item.note_nodeset.find { |note| note['type'] == 'preferred citation' }
|
47
46
|
|
48
47
|
element_text(citation) if citation
|
49
48
|
end
|
50
49
|
end
|
51
50
|
|
52
51
|
def reference_title(item)
|
53
|
-
[item.
|
52
|
+
[item.titleInfo_nodeset,
|
54
53
|
item.originInfo.dateOther,
|
55
54
|
item.part.detail.number,
|
56
|
-
item.
|
57
|
-
end
|
58
|
-
|
59
|
-
def related_item_is_a_location?(item)
|
60
|
-
!related_item_is_a_collection?(item) &&
|
61
|
-
!related_item_is_a_reference?(item) &&
|
62
|
-
item.location.length.positive? &&
|
63
|
-
item.titleInfo.empty?
|
64
|
-
end
|
65
|
-
|
66
|
-
def related_item_is_a_reference?(item)
|
67
|
-
!related_item_is_a_collection?(item) &&
|
68
|
-
item.attributes['type'].respond_to?(:value) &&
|
69
|
-
item.attributes['type'].value == 'isReferencedBy'
|
55
|
+
item.note_nodeset].flatten.compact.map!(&:text).map!(&:strip).join(' ')
|
70
56
|
end
|
71
57
|
|
72
58
|
def related_item_label(item)
|
@@ -74,9 +60,9 @@ module ModsDisplay
|
|
74
60
|
displayLabel(item)
|
75
61
|
else
|
76
62
|
case
|
77
|
-
when
|
63
|
+
when item.location?
|
78
64
|
return I18n.t('mods_display.location')
|
79
|
-
when
|
65
|
+
when item.reference?
|
80
66
|
return I18n.t('mods_display.referenced_by')
|
81
67
|
end
|
82
68
|
I18n.t('mods_display.related_item')
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ModsDisplay
|
4
|
+
class NameFormatter
|
5
|
+
def self.format(element)
|
6
|
+
new(element).format
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(element)
|
10
|
+
@element = element
|
11
|
+
end
|
12
|
+
|
13
|
+
def format
|
14
|
+
return element_text(display_form_nodeset) if display_form_nodeset.present?
|
15
|
+
return name_parts if name_parts.present?
|
16
|
+
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_reader :element
|
23
|
+
|
24
|
+
def name_parts
|
25
|
+
@name_parts ||= begin
|
26
|
+
output = [unqualified_name_parts(name_part_nodeset),
|
27
|
+
qualified_name_parts(name_part_nodeset, 'family'),
|
28
|
+
qualified_name_parts(name_part_nodeset, 'given')].flatten.compact.join(', ')
|
29
|
+
terms = qualified_name_parts(name_part_nodeset, 'termsOfAddress')
|
30
|
+
unless terms.empty?
|
31
|
+
term_delimiter = ', '
|
32
|
+
term_delimiter = ' ' if name_part_begins_with_roman_numeral?(terms.first)
|
33
|
+
output = [output, terms.join(', ')].flatten.compact.join(term_delimiter)
|
34
|
+
end
|
35
|
+
dates = qualified_name_parts(name_part_nodeset, 'date')
|
36
|
+
output = [output, dates].flatten.compact.join(', ') unless dates.empty?
|
37
|
+
output
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def unqualified_name_parts(name_part_nodeset)
|
42
|
+
name_part_nodeset.map do |part|
|
43
|
+
element_text(part) unless part.attributes['type']
|
44
|
+
end.compact
|
45
|
+
end
|
46
|
+
|
47
|
+
def qualified_name_parts(name_part_nodeset, type)
|
48
|
+
name_part_nodeset.map do |part|
|
49
|
+
element_text(part) if part.get_attribute('type') == type
|
50
|
+
end.compact
|
51
|
+
end
|
52
|
+
|
53
|
+
def name_part_begins_with_roman_numeral?(part)
|
54
|
+
first_part = part.split(/\s|,/).first.strip
|
55
|
+
first_part.chars.all? do |char|
|
56
|
+
%w[I X C L V].include? char
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def element_text(element)
|
61
|
+
element.text.strip
|
62
|
+
end
|
63
|
+
|
64
|
+
def name_part_nodeset
|
65
|
+
@name_part_nodeset ||= element.xpath('mods:namePart', mods: MODS_NS)
|
66
|
+
end
|
67
|
+
|
68
|
+
def display_form_nodeset
|
69
|
+
@display_form_nodeset ||= element.xpath('mods:displayForm', mods: MODS_NS)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -5,25 +5,60 @@ module ModsDisplay
|
|
5
5
|
private
|
6
6
|
|
7
7
|
def render_nested_related_item?(item)
|
8
|
-
|
8
|
+
item.constituent? || item.host?
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
item.typeOfResource.attributes.first.key?('collection') &&
|
16
|
-
item.typeOfResource.attributes.first['collection'].value == 'yes'
|
17
|
-
end
|
11
|
+
class RelatedItemValue < SimpleDelegator
|
12
|
+
def collection?
|
13
|
+
@collection ||= typeOfResource_nodeset.first&.get_attribute('collection') == 'yes'
|
14
|
+
end
|
18
15
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
16
|
+
def constituent?
|
17
|
+
@constituent ||= type_attribute == 'constituent'
|
18
|
+
end
|
19
|
+
|
20
|
+
def host?
|
21
|
+
@host ||= type_attribute == 'host'
|
22
|
+
end
|
23
|
+
|
24
|
+
def location?
|
25
|
+
@location ||= !collection? &&
|
26
|
+
!reference? &&
|
27
|
+
location_nodeset.length.positive? &&
|
28
|
+
titleInfo_nodeset.empty?
|
29
|
+
end
|
30
|
+
|
31
|
+
def reference?
|
32
|
+
@reference ||= !collection? && type_attribute == 'isReferencedBy'
|
33
|
+
end
|
34
|
+
|
35
|
+
def typeOfResource_nodeset
|
36
|
+
@typeOfResource_nodeset ||= xpath('mods:typeOfResource', mods: MODS_NS)
|
37
|
+
end
|
38
|
+
|
39
|
+
def location_nodeset
|
40
|
+
@location_nodeset ||= xpath('mods:location', mods: MODS_NS)
|
41
|
+
end
|
42
|
+
|
43
|
+
def location_url_nodeset
|
44
|
+
@location_url_nodeset ||= xpath('mods:location/mods:url', mods: MODS_NS)
|
45
|
+
end
|
46
|
+
|
47
|
+
def titleInfo_nodeset
|
48
|
+
@titleInfo_nodeset ||= xpath('mods:titleInfo', mods: MODS_NS)
|
49
|
+
end
|
50
|
+
|
51
|
+
def note_nodeset
|
52
|
+
@note_nodeset ||= xpath('mods:note', mods: MODS_NS)
|
53
|
+
end
|
54
|
+
|
55
|
+
def type_attribute
|
56
|
+
@type_attribute ||= get_attribute('type')
|
57
|
+
end
|
23
58
|
|
24
|
-
|
25
|
-
|
26
|
-
|
59
|
+
def self.for_values(values)
|
60
|
+
values.map { |value| new(value) }
|
61
|
+
end
|
27
62
|
end
|
28
63
|
end
|
29
64
|
end
|
data/lib/mods_display/version.rb
CHANGED
data/lib/mods_display.rb
CHANGED
@@ -5,6 +5,7 @@ require 'mods_display/html'
|
|
5
5
|
require 'mods_display/country_codes'
|
6
6
|
require 'mods_display/relator_codes'
|
7
7
|
require 'mods_display/related_item_concerns'
|
8
|
+
require 'mods_display/name_formatter'
|
8
9
|
require 'mods_display/fields/field'
|
9
10
|
require 'mods_display/fields/abstract'
|
10
11
|
require 'mods_display/fields/access_condition'
|
@@ -40,6 +41,8 @@ I18n::Backend::Simple.include I18n::Backend::Fallbacks
|
|
40
41
|
I18n.load_path += Dir["#{File.expand_path('..', __dir__)}/config/locales/*.yml"]
|
41
42
|
I18n.backend.load_translations
|
42
43
|
|
44
|
+
MODS_NS = 'http://www.loc.gov/mods/v3'
|
45
|
+
|
43
46
|
begin
|
44
47
|
require 'rails'
|
45
48
|
rescue LoadError
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mods_display
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jessie Keck
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-11-
|
11
|
+
date: 2023-11-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: stanford-mods
|
@@ -223,6 +223,7 @@ files:
|
|
223
223
|
- lib/mods_display/fields/title.rb
|
224
224
|
- lib/mods_display/fields/values.rb
|
225
225
|
- lib/mods_display/html.rb
|
226
|
+
- lib/mods_display/name_formatter.rb
|
226
227
|
- lib/mods_display/related_item_concerns.rb
|
227
228
|
- lib/mods_display/relator_codes.rb
|
228
229
|
- lib/mods_display/version.rb
|
@@ -245,7 +246,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
245
246
|
- !ruby/object:Gem::Version
|
246
247
|
version: '0'
|
247
248
|
requirements: []
|
248
|
-
rubygems_version: 3.
|
249
|
+
rubygems_version: 3.3.7
|
249
250
|
signing_key:
|
250
251
|
specification_version: 4
|
251
252
|
summary: The MODS Display gem allows implementers to configure a customized display
|