mods_display 1.2.1 → 1.3.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: c13877b6d0839a4341a26072d23f3e31ed3d27e173f05bb0b1cbbc6e5c0d77b1
4
- data.tar.gz: d99b93bfb31352d75299990cea5810ce6668c06035fa5aa90d4ffd3f4fb31f0d
3
+ metadata.gz: 7e56a492203162fcc4977642c25ae1480279abb98addbb8b37fc89c5d508ec1b
4
+ data.tar.gz: f2b56fb5a9273fc3ae27aac611737d80adc0d825c29aada98377468697912c17
5
5
  SHA512:
6
- metadata.gz: 281488c21b60e419dc943a7af91a08f0ab32c4ba92e6ed276b1c86ab0b64722c87a4915f81b482e25c968ecc3855da7736b2b699a0dc6534635bf1822cf73ab1
7
- data.tar.gz: cebd18e35b4c81f9ac2dc3d2251a1bf9f8af7e2d9d36e1adc0561e33c48c5ca05faf057f8cd8df1943294aebd2a70914c9a25d7cf893e6aff3dd2e08061057af
6
+ metadata.gz: 52c2b74b30ddf95a6c04ec094ff3c9f064c7282898030f0d81507bebbf8eb45babc9f80edd9e4ef3e0149a1ae730519cb45eff174b6f39cae2f06768c9fe893c
7
+ data.tar.gz: b5ddfbde80b819cf3eed221e9d338e1526ca42ebc4289125cdfb34a07632da0e28a71920690e17f7c25c766997730deb24b50b5a03a0a206ab101781917119cb
@@ -39,163 +39,20 @@ module ModsDisplay
39
39
  end
40
40
  end
41
41
 
42
- def date_values(element)
43
- date_field_keys.map do |date_field|
44
- next unless element.respond_to?(date_field)
42
+ def date_values(element, date_field_keys: %i[dateCreated dateCaptured dateValid dateModified copyrightDate])
43
+ imprint = Stanford::Mods::Imprint.new(element)
45
44
 
46
- elements = element.send(date_field)
47
- next if elements.empty?
45
+ date_field_keys.map do |date_field|
46
+ date_values = imprint.dates([date_field])
47
+ next if date_values.empty?
48
48
 
49
49
  ModsDisplay::Values.new(
50
- label: displayLabel(element) || pub_info_labels[elements.first.name.to_sym],
51
- values: parse_dates(elements)
50
+ label: displayLabel(element) || pub_info_labels[date_field],
51
+ values: select_the_best_date(date_values)
52
52
  )
53
53
  end.compact
54
54
  end
55
55
 
56
- class DateValue
57
- attr_reader :value
58
- delegate :text, :date, :point, :qualifier, :encoding, to: :value
59
-
60
- def initialize(value)
61
- @value = value
62
- end
63
-
64
- # True if the element text isn't blank or the placeholder "9999".
65
- def valid?
66
- text.present? && !['9999', '0000-00-00', 'uuuu'].include?(text.strip)
67
- end
68
-
69
- # Element text reduced to digits and hyphen. Captures date ranges and
70
- # negative (BCE) dates. Used for comparison/deduping.
71
- def base_value
72
- if text =~ /^\[?1\d{3}-\d{2}\??\]?$/
73
- return text.sub(/(\d{2})(\d{2})-(\d{2})/, '\1\2-\1\3')
74
- end
75
-
76
- text.gsub(/(?<![\d])(\d{1,3})([xu-]{1,3})/i) { "#{$1}#{'0' * $2.length}"}.scan(/[\d-]/).join
77
- end
78
-
79
- # Decoded version of the date, if it was encoded. Strips leading zeroes.
80
- def decoded_value
81
- return text.strip unless date
82
-
83
- unless encoding.present?
84
- return text.strip unless text =~ /^-?\d+$/ || text =~ /^[\dXxu?-]{4}$/
85
- end
86
-
87
- # Delegate to the appropriate decoding method, if any
88
- case value.precision
89
- when :day
90
- date.strftime('%B %e, %Y')
91
- when :month
92
- date.strftime('%B %Y')
93
- when :year
94
- year = date.year
95
- if year < 1
96
- "#{year.abs + 1} BCE"
97
- # Any dates before the year 1000 are explicitly marked CE
98
- elsif year > 1 && year < 1000
99
- "#{year} CE"
100
- else
101
- year.to_s
102
- end
103
- when :century
104
- return "#{(date.to_s[0..1].to_i + 1).ordinalize} century"
105
- when :decade
106
- return "#{date.year}s"
107
- else
108
- text.strip
109
- end
110
- end
111
-
112
- # Decoded date with "BCE" or "CE" and qualifier markers. See (outdated):
113
- # https://consul.stanford.edu/display/chimera/MODS+display+rules#MODSdisplayrules-3b.%3CoriginInfo%3E
114
- def qualified_value
115
- date = decoded_value
116
-
117
- return "[ca. #{date}]" if qualifier == 'approximate'
118
- return "[#{date}?]" if qualifier == 'questionable'
119
- return "[#{date}]" if qualifier == 'inferred'
120
-
121
- date
122
- end
123
- end
124
-
125
- class DateRange
126
- def initialize(start: nil, stop: nil)
127
- @start = start
128
- @stop = stop
129
- end
130
-
131
- # Base value as hyphen-joined string. Used for comparison/deduping.
132
- def base_value
133
- "#{@start&.base_value}-#{@stop&.base_value}"
134
- end
135
-
136
- # Base values as array. Used for comparison/deduping of individual dates.
137
- def base_values
138
- [@start&.base_value, @stop&.base_value].compact
139
- end
140
-
141
- # The encoding value for the start of the range, or stop if not present.
142
- def encoding
143
- @start&.encoding || @stop&.encoding
144
- end
145
-
146
- # Decoded dates with "BCE" or "CE" and qualifier markers applied to
147
- # the entire range, or individually if dates differ.
148
- def qualified_value
149
- if @start&.qualifier == @stop&.qualifier
150
- qualifier = @start&.qualifier || @stop&.qualifier
151
- date = "#{@start&.decoded_value}-#{@stop&.decoded_value}"
152
- return "[ca. #{date}]" if qualifier == 'approximate'
153
- return "[#{date}?]" if qualifier == 'questionable'
154
- return "[#{date}]" if qualifier == 'inferred'
155
-
156
- date
157
- else
158
- "#{@start&.qualified_value}-#{@stop&.qualified_value}"
159
- end
160
- end
161
- end
162
- def parse_dates(elements)
163
- # convert to DateValue objects and keep only valid ones
164
- dates = elements.map(&:as_object).flatten.map { |element| DateValue.new(element) }.select(&:valid?)
165
-
166
- # join any date ranges into DateRange objects
167
- point, nonpoint = dates.partition(&:point)
168
- if point.any?
169
- range = DateRange.new(start: point.find { |date| date.point == 'start' },
170
- stop: point.find { |date| date.point == 'end' })
171
- nonpoint.unshift(range)
172
- end
173
- dates = nonpoint
174
-
175
- # ensure dates are unique with respect to their base values
176
- dates = dates.group_by(&:base_value).map do |_value, group|
177
- group.first if group.one?
178
-
179
- # if one of the duplicates wasn't encoded, use that one. see:
180
- # https://consul.stanford.edu/display/chimera/MODS+display+rules#MODSdisplayrules-3b.%3CoriginInfo%3E
181
- if group.reject(&:encoding).any?
182
- group.reject(&:encoding).first
183
-
184
- # otherwise just randomly pick the last in the group
185
- else
186
- group.last
187
- end
188
- end
189
-
190
- # if any single dates are already part of a range, discard them
191
- range_base_values = dates.select { |date| date.is_a?(DateRange) }
192
- .map(&:base_values).flatten
193
- dates = dates.reject { |date| range_base_values.include?(date.base_value) }
194
-
195
- # output formatted dates with qualifiers, CE/BCE, etc.
196
- dates.map(&:qualified_value)
197
- end
198
-
199
56
  def other_pub_info(element)
200
57
  element.children.select do |child|
201
58
  pub_info_parts.include?(child.name.to_sym)
@@ -278,11 +135,14 @@ module ModsDisplay
278
135
  compact_and_join_with_delimiter(publishers, ' : ')
279
136
  end
280
137
 
281
- def parts_element(value)
282
- date_elements = %w[dateIssued dateOther].map do |date_field_name|
283
- next unless value.respond_to?(date_field_name.to_sym)
138
+ def parts_element(value, date_field_keys: %i[dateIssued dateOther])
139
+ imprint = Stanford::Mods::Imprint.new(value)
284
140
 
285
- parse_dates(value.send(date_field_name.to_sym))
141
+ date_elements = date_field_keys.map do |date_field|
142
+ date_values = imprint.dates([date_field])
143
+ next if date_values.empty?
144
+
145
+ select_the_best_date(date_values)
286
146
  end.flatten.compact.reject do |date|
287
147
  date.strip.empty?
288
148
  end.map(&:strip)
@@ -293,10 +153,6 @@ module ModsDisplay
293
153
  %i[issuance frequency]
294
154
  end
295
155
 
296
- def date_field_keys
297
- %i[dateCreated dateCaptured dateValid dateModified copyrightDate]
298
- end
299
-
300
156
  def pub_info_labels
301
157
  { dateCreated: I18n.t('mods_display.date_created'),
302
158
  dateCaptured: I18n.t('mods_display.date_captured'),
@@ -306,5 +162,30 @@ module ModsDisplay
306
162
  issuance: I18n.t('mods_display.issuance'),
307
163
  frequency: I18n.t('mods_display.frequency') }
308
164
  end
165
+
166
+ def select_the_best_date(dates)
167
+ # ensure dates are unique with respect to their base values
168
+ dates = dates.group_by(&:base_value).map do |_value, group|
169
+ group.first if group.one?
170
+
171
+ # if one of the duplicates wasn't encoded, use that one. see:
172
+ # https://consul.stanford.edu/display/chimera/MODS+display+rules#MODSdisplayrules-3b.%3CoriginInfo%3E
173
+ if group.reject(&:encoding).any?
174
+ group.reject(&:encoding).first
175
+
176
+ # otherwise just randomly pick the last in the group
177
+ else
178
+ group.last
179
+ end
180
+ end
181
+
182
+ # if any single dates are already part of a range, discard them
183
+ range_base_values = dates.select { |date| date.is_a?(Stanford::Mods::Imprint::DateRange) }
184
+ .map(&:base_values).flatten
185
+ dates = dates.reject { |date| range_base_values.include?(date.base_value) }
186
+
187
+ # output formatted dates with qualifiers, CE/BCE, etc.
188
+ dates.map(&:qualified_value)
189
+ end
309
190
  end
310
191
  end
@@ -30,6 +30,11 @@ module ModsDisplay
30
30
  '<br />'
31
31
  end
32
32
 
33
+ # Override of Field#element_text to get text rather than HTML
34
+ def element_text(element)
35
+ element.text.strip
36
+ end
37
+
33
38
  def collapse_roles(fields)
34
39
  return [] if fields.blank?
35
40
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ModsDisplay
4
- VERSION = '1.2.1'
4
+ VERSION = '1.3.0'
5
5
  end
metadata CHANGED
@@ -1,35 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mods_display
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.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: 2022-07-14 00:00:00.000000000 Z
11
+ date: 2023-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: stanford-mods
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 3.0.0.alpha1
20
- - - "<"
17
+ - - "~>"
21
18
  - !ruby/object:Gem::Version
22
- version: '4'
19
+ version: '3.3'
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: 3.0.0.alpha1
30
- - - "<"
24
+ - - "~>"
31
25
  - !ruby/object:Gem::Version
32
- version: '4'
26
+ version: '3.3'
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: i18n
35
29
  requirement: !ruby/object:Gem::Requirement
@@ -226,7 +220,6 @@ files:
226
220
  - lib/mods_display/related_item_concerns.rb
227
221
  - lib/mods_display/relator_codes.rb
228
222
  - lib/mods_display/version.rb
229
- - mods_display.gemspec
230
223
  homepage: https://github.com/sul-dlss/mods_display
231
224
  licenses: []
232
225
  metadata: {}
@@ -245,7 +238,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
245
238
  - !ruby/object:Gem::Version
246
239
  version: '0'
247
240
  requirements: []
248
- rubygems_version: 3.3.7
241
+ rubygems_version: 3.3.26
249
242
  signing_key:
250
243
  specification_version: 4
251
244
  summary: The MODS Display gem allows implementers to configure a customized display
data/mods_display.gemspec DELETED
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
- require_relative "lib/mods_display/version"
3
-
4
- Gem::Specification.new do |gem|
5
- gem.name = 'mods_display'
6
- gem.version = ModsDisplay::VERSION
7
- gem.authors = ['Jessie Keck']
8
- gem.email = ['jessie.keck@gmail.com']
9
- gem.description = 'MODS Display is a gem to centralize the display logic of MODS medadata.'
10
- gem.summary = 'The MODS Display gem allows implementers to configure a customized display of MODS metadata. This display implements the specifications defined at Stanford for how to display MODS.'
11
- gem.homepage = 'https://github.com/sul-dlss/mods_display'
12
-
13
- # Specify which files should be added to the gem when it is released.
14
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
15
- gem.files = Dir.chdir(File.expand_path(__dir__)) do
16
- `git ls-files -z`.split("\x0").reject do |f|
17
- (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
18
- end
19
- end
20
- gem.bindir = "exe"
21
- gem.executables = gem.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
22
- gem.require_paths = ["lib"]
23
-
24
- gem.add_dependency 'stanford-mods', '>= 3.0.0.alpha1', '< 4'
25
- gem.add_dependency 'i18n'
26
- gem.add_dependency 'view_component'
27
-
28
- gem.add_development_dependency 'rake'
29
- gem.add_development_dependency 'rspec', '~> 3.0'
30
- gem.add_development_dependency 'rspec-rails'
31
- gem.add_development_dependency 'rubocop'
32
- gem.add_development_dependency 'capybara'
33
- gem.add_development_dependency 'byebug'
34
- gem.add_development_dependency 'rails', ENV['RAILS_VERSION'] || '~> 6.0'
35
- gem.add_development_dependency 'combustion', '~> 1.3'
36
- end