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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db5aacb765a91a03b8fe5fbb6c41b52ab0cb2f94467808f5e896f9b95c5b72ad
4
- data.tar.gz: b0572788c7868f49d98340668a28e71dde9cd41f676927436ce2ec9d09f24f83
3
+ metadata.gz: cd385f9d4aea6c14524378831877c327c6fdfd2664356e148b457af9c26a5623
4
+ data.tar.gz: b66857f71c766dc6edb03b8783d1d63486e94c63c8e9a71a0474f6b5a11d44cc
5
5
  SHA512:
6
- metadata.gz: 283a91d3efc90f2cdac50c2adae6133e758084ed454bbc9c79000567d9f83696e15369089290609c709e2c38b4e9e02a19d264297ff48e529aaf232bfd02f773
7
- data.tar.gz: a22877a514a7379219856dc941dfca980eb23aa7c8b0d2e8f12a8d023300dee4655ca1ef7e87e3ec36fe980c524eb07af848425d8b920b5d41324ae995871751
6
+ metadata.gz: 6b4760e8eee0c1eef22badaf5087b4095c4c88766c3b128bbaa1e841e2b1aa34294ced0be7199875b6aa57cdf1b3385dd5c11d624f4ce818afcc7fa4f1da25ab
7
+ data.tar.gz: 93c93c4249b55816c9716b1c632d0b4c5b5a2874365e33139fbbf6cd9421f01d3aa9800d347c72ae7837bcf98ef763650e8151a3cab547cecb287a72ff7a9ace
data/.rubocop.yml CHANGED
@@ -29,4 +29,10 @@ RSpec/MultipleExpectations:
29
29
  Enabled: false
30
30
 
31
31
  RSpec/ExampleLength:
32
+ Enabled: false
33
+
34
+ Naming/MethodName:
35
+ Enabled: false
36
+
37
+ Naming/VariableName:
32
38
  Enabled: false
@@ -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.placeTerm.select do |term|
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.placeTerm.map do |term|
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.placeTerm.any? do |term|
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
- name_identifiers = value.element_children.select { |child| child.name == 'nameIdentifier' }
12
- person = if value.displayForm.length.positive?
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.present? && element.role.roleTerm.present?
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.attribute('type')&.value == 'orcid'
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 related_item_is_a_collection?(value)
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 related_item_is_a_constituent?(item)
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 related_item_is_a_collection?(value)
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 related_item_is_a_location?(item)
29
- element_text(item.location)
30
- elsif related_item_is_a_reference?(item)
28
+ if item.location?
29
+ element_text(item.location_nodeset)
30
+ elsif item.reference?
31
31
  reference_title(item)
32
- elsif item.titleInfo.any?
33
- title = element_text(item.titleInfo)
32
+ elsif item.titleInfo_nodeset.any?
33
+ title = element_text(item.titleInfo_nodeset)
34
34
  location = nil
35
- location = element_text(item.location.url) if item.location.length.positive? &&
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.note.any?
46
- citation = item.note.find { |note| note['type'] == 'preferred citation' }
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.titleInfo,
52
+ [item.titleInfo_nodeset,
54
53
  item.originInfo.dateOther,
55
54
  item.part.detail.number,
56
- item.note].flatten.compact.map!(&:text).map!(&:strip).join(' ')
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 related_item_is_a_location?(item)
63
+ when item.location?
78
64
  return I18n.t('mods_display.location')
79
- when related_item_is_a_reference?(item)
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
- related_item_is_a_constituent?(item) || related_item_is_host?(item)
8
+ item.constituent? || item.host?
9
9
  end
10
10
 
11
- def related_item_is_a_collection?(item)
12
- item.respond_to?(:titleInfo) &&
13
- item.respond_to?(:typeOfResource) &&
14
- !item.typeOfResource.attributes.empty? &&
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
- def related_item_is_a_constituent?(item)
20
- item.attributes['type'].respond_to?(:value) &&
21
- item.attributes['type'].value == 'constituent'
22
- end
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
- def related_item_is_host?(item)
25
- item.attributes['type'].respond_to?(:value) &&
26
- item.attributes['type'].value == 'host'
59
+ def self.for_values(values)
60
+ values.map { |value| new(value) }
61
+ end
27
62
  end
28
63
  end
29
64
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ModsDisplay
4
- VERSION = '1.3.4'
4
+ VERSION = '1.4.0'
5
5
  end
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.3.4
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-01 00:00:00.000000000 Z
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.4.10
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