mods_display 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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