cocina_display 2.0.0 → 2.1.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: f3f339ed91ca38de77fe91e83e50ba0dbdae117c810b831ed7597181b949dab7
4
- data.tar.gz: 10e954dc692155b1c2ea3e219840431b4bae188b09399060973bc873b5dc9d63
3
+ metadata.gz: ac41e805ba8d1ab521f7d647a0407c7c0cc02840bd3bde547c4ef5a017b32dca
4
+ data.tar.gz: ca2d3190ea5e1b9e83f504343fbfc9af462cdd0b4a51e615c623a33ceaef7e21
5
5
  SHA512:
6
- metadata.gz: 04f6b7138b9079fb12f9455e5363fce77743f19e0ae30aa01a2d13a567182d184475304316bfa81d720970cbab77ac7d8854f29e62bbcf15df43cf95593898eb
7
- data.tar.gz: 791231009d1e945f959bae16095d022306052bf0a8a02fe76f3d722343e79434469fd1bf5e32309a638afda378a8070e7f8dd259adce155106c307808a1602c4
6
+ metadata.gz: 6962854fc5bffc3288692a8feb183f098adba9f3c0f4f424db58d326e87a2d63f534fc06ea644124d6e37fd2fb0846f2970e49348b70f96a4269b2a0f0c53ab0
7
+ data.tar.gz: 1650a3791e4236bc2cc9fdbbcd9b4920c670a5c5fb52acc3122b3bea5755efe69d31a61496f3c41f1d8f4defa125791fd38a872d2a75f58055acf5ab41cde0f2
@@ -126,7 +126,10 @@ module CocinaDisplay
126
126
  # All root level events associated with the object.
127
127
  # @return [Array<CocinaDisplay::Events::Event>]
128
128
  def events
129
- @events ||= path("$.description.event.*").map { |event| CocinaDisplay::Events::Event.new(event) }
129
+ @events ||= path("$.description.event.*").map do |cocina|
130
+ event = CocinaDisplay::Events::Event.new(cocina)
131
+ event.imprint? ? CocinaDisplay::Events::Imprint.new(cocina) : event
132
+ end
130
133
  end
131
134
 
132
135
  # The adminMetadata creation event (When was it was deposited?)
@@ -144,12 +147,9 @@ module CocinaDisplay
144
147
  end
145
148
 
146
149
  # Array of CocinaDisplay::Imprint objects for all relevant Cocina events.
147
- # Considers publication, creation, capture, and copyright events.
148
- # Considers event types as well as date types if the event is untyped.
149
- # Prefers events where the date was not encoded, if any.
150
- # @return [Array<CocinaDisplay::Imprint>] The list of Imprint objects
150
+ # @return [Array<CocinaDisplay::Imprint>]
151
151
  def imprint_events
152
- events.filter(&:imprint?)
152
+ events.filter { |event| event.is_a? CocinaDisplay::Events::Imprint }
153
153
  end
154
154
 
155
155
  # All dates associated with the object via an event.
@@ -16,7 +16,7 @@ module CocinaDisplay
16
16
  # @note Also supports `event1.between?(event2, event3)` via {Comparable}.
17
17
  # @return [Integer, nil]
18
18
  def <=>(other)
19
- [unique_dates_for_display] <=> [other.unique_dates_for_display] if other.is_a?(Event)
19
+ [dates] <=> [other.dates] if other.is_a?(Event)
20
20
  end
21
21
 
22
22
  # The display label for the event.
@@ -26,7 +26,6 @@ module CocinaDisplay
26
26
  # @return [String]
27
27
  def label
28
28
  return cocina["displayLabel"] if cocina["displayLabel"].present?
29
- return "Imprint" if imprint?
30
29
  return dates.map(&:label).first if date_only?
31
30
 
32
31
  type&.capitalize || date_types.first&.capitalize || "Event"
@@ -80,7 +79,10 @@ module CocinaDisplay
80
79
  # @note Unencoded dates or no dates often indicate an imprint statement.
81
80
  # @return [Boolean]
82
81
  def imprint?
83
- (has_type?("publication") || types.empty?) && (dates.none?(&:encoding?) || dates.none?)
82
+ contributors.present? &&
83
+ locations.present? &&
84
+ (has_type?("publication") || types.empty?) &&
85
+ (dates.any? { |date| !date.encoding? } || dates.none?)
84
86
  end
85
87
 
86
88
  # All contributors associated with this event.
@@ -107,49 +109,11 @@ module CocinaDisplay
107
109
  end
108
110
  end
109
111
 
110
- # String representation of the event using edition, dates, locations, and contributors.
111
- # Format is inspired by typical imprint statements for books.
112
+ # String representation of the event using date and location.
112
113
  # @return [String]
113
- # @example "2nd ed. - New York : John Doe, 1999"
114
+ # @example "John Doe, New York (State), 1999"
114
115
  def to_s
115
- place_contrib = Utils.compact_and_join([place_str, contributor_str], delimiter: " : ")
116
- note_place_contrib = Utils.compact_and_join([edition_note_str, place_contrib], delimiter: " - ")
117
- Utils.compact_and_join([note_place_contrib, date_str, copyright_note_str], delimiter: ", ")
118
- end
119
-
120
- # Filter dates for uniqueness using base value according to predefined rules.
121
- # 1. For a group of dates with the same base value, choose a single one
122
- # 2. Prefer unencoded dates over encoded ones when choosing a single date
123
- # 3. Remove date ranges that duplicate any unencoded non-range dates
124
- # @return [Array<CocinaDisplay::Dates::Date>]
125
- # @see CocinaDisplay::Dates::Date#base_value
126
- # @see https://consul.stanford.edu/display/chimera/MODS+display+rules#MODSdisplayrules-3b.%3CoriginInfo%3E
127
- def unique_dates_for_display
128
- # Choose a single date for each group with the same base value
129
- deduped_dates = dates.group_by(&:base_value).map do |base_value, group|
130
- if (unencoded = group.reject(&:encoding?)).any?
131
- unencoded.first
132
- else
133
- group.first
134
- end
135
- end
136
-
137
- # Remove any ranges that duplicate part of an unencoded non-range date
138
- ranges, singles = deduped_dates.partition { |date| date.is_a?(CocinaDisplay::Dates::DateRange) }
139
- unencoded_singles_dates = singles.reject(&:encoding?).flat_map(&:to_a)
140
- ranges.reject! { |date_range| unencoded_singles_dates.any? { |date| date_range.as_range.include?(date) } }
141
-
142
- (singles + ranges).sort
143
- end
144
-
145
- # Filter locations to display according to predefined rules.
146
- # 1. Prefer unencoded locations (plain value) over encoded ones
147
- # 2. If no unencoded locations but there are MARC country codes, decode them
148
- # 3. Keep only unique locations after decoding
149
- def locations_for_display
150
- unencoded_locs, encoded_locs = locations.partition { |loc| loc.unencoded_value? }
151
- locs_for_display = unencoded_locs.presence || encoded_locs
152
- locs_for_display.map(&:to_s).compact_blank.uniq
116
+ Utils.compact_and_join([place_str, date_str], delimiter: ", ")
153
117
  end
154
118
 
155
119
  # Union of event's type and its date types.
@@ -168,34 +132,38 @@ module CocinaDisplay
168
132
  to_s == date_str
169
133
  end
170
134
 
171
- # The date portion of the imprint statement, comprising all unique dates.
172
- # @return [String]
173
- def date_str
174
- Utils.compact_and_join(unique_dates_for_display.map(&:to_s), delimiter: "; ")
175
- end
135
+ # The dates associated with this event that should be used for display.
136
+ # Prefers encoded dates when there are duplicates.
137
+ # @return [Array<CocinaDisplay::Dates::Date>]
138
+ def display_dates
139
+ # Choose a single date for each group with the same base value;
140
+ # prefer encoded dates when there are duplicates.
141
+ deduped_dates = dates.group_by(&:base_value).map do |base_value, group|
142
+ if (encoded = group.filter(&:encoding?)).any?
143
+ encoded.first
144
+ else
145
+ group.first
146
+ end
147
+ end
176
148
 
177
- # Edition notes associated with the event as a single string.
178
- # @return [String]
179
- def edition_note_str
180
- Utils.compact_and_join(notes.filter { |note| note.type == "edition" }.map(&:to_s), delimiter: ", ")
181
- end
149
+ # Remove any ranges that duplicate part of an encoded non-range date
150
+ ranges, singles = deduped_dates.partition { |date| date.is_a?(CocinaDisplay::Dates::DateRange) }
151
+ encoded_singles_dates = singles.filter(&:encoding?).flat_map(&:to_a)
152
+ ranges.reject! { |date_range| encoded_singles_dates.any? { |date| date_range.as_range.include?(date) } }
182
153
 
183
- # Copyright notes associated with the event as a single string.
184
- # @return [String]
185
- def copyright_note_str
186
- Utils.compact_and_join(notes.filter { |note| note.type == "copyright statement" }.map(&:to_s), delimiter: ", ")
154
+ (singles + ranges).sort
187
155
  end
188
156
 
189
- # All contributors associated with the event as a single string.
157
+ # Dates associated with this event as a single string.
190
158
  # @return [String]
191
- def contributor_str
192
- Utils.compact_and_join(contributors.map(&:display_name), delimiter: " : ")
159
+ def date_str
160
+ display_dates.map(&:qualified_value).compact_blank.uniq.to_sentence
193
161
  end
194
162
 
195
- # The place of publication, combining all location values.
163
+ # Locations associated with this event as a single string.
196
164
  # @return [String]
197
165
  def place_str
198
- Utils.compact_and_join(locations_for_display, delimiter: " : ")
166
+ locations.map(&:to_s).compact_blank.uniq.join(", ")
199
167
  end
200
168
  end
201
169
  end
@@ -0,0 +1,89 @@
1
+ module CocinaDisplay
2
+ module Events
3
+ # An imprint statement associated with an object.
4
+ class Imprint < Event
5
+ # Imprints are labelled "Imprint" unless overridden by a displayLabel.
6
+ # @return [String]
7
+ def label
8
+ cocina["displayLabel"].presence || "Imprint"
9
+ end
10
+
11
+ # Imprint statement for a book, formatted using typical conventions.
12
+ # @return [String]
13
+ # @example "2nd ed. - New York : John Doe, 1999"
14
+ def to_s
15
+ place_contrib = Utils.compact_and_join([place_str, contributor_str], delimiter: " : ")
16
+ note_place_contrib = Utils.compact_and_join([edition_note_str, place_contrib], delimiter: " - ")
17
+ Utils.compact_and_join([note_place_contrib, date_str, copyright_note_str], delimiter: ", ")
18
+ end
19
+
20
+ private
21
+
22
+ # Filter dates for uniqueness using base value according to predefined rules.
23
+ # 1. For a group of dates with the same base value, choose a single one
24
+ # 2. Prefer unencoded dates over encoded ones when choosing a single date
25
+ # 3. Remove date ranges that duplicate any unencoded non-range dates
26
+ # @return [Array<CocinaDisplay::Dates::Date>]
27
+ # @see CocinaDisplay::Dates::Date#base_value
28
+ # @see https://consul.stanford.edu/display/chimera/MODS+display+rules#MODSdisplayrules-3b.%3CoriginInfo%3E
29
+ def display_dates
30
+ # Choose a single date for each group with the same base value
31
+ deduped_dates = dates.group_by(&:base_value).map do |base_value, group|
32
+ if (unencoded = group.reject(&:encoding?)).any?
33
+ unencoded.first
34
+ else
35
+ group.first
36
+ end
37
+ end
38
+
39
+ # Remove any ranges that duplicate part of an unencoded non-range date
40
+ ranges, singles = deduped_dates.partition { |date| date.is_a?(CocinaDisplay::Dates::DateRange) }
41
+ unencoded_singles_dates = singles.reject(&:encoding?).flat_map(&:to_a)
42
+ ranges.reject! { |date_range| unencoded_singles_dates.any? { |date| date_range.as_range.include?(date) } }
43
+
44
+ (singles + ranges).sort
45
+ end
46
+
47
+ # Filter locations to display according to predefined rules.
48
+ # 1. Prefer unencoded locations (plain value) over encoded ones
49
+ # 2. If no unencoded locations but there are MARC country codes, decode them
50
+ # 3. Keep only unique locations after decoding
51
+ # @return [Array<String>]
52
+ def display_locations
53
+ unencoded_locs, encoded_locs = locations.partition { |loc| loc.unencoded_value? }
54
+ locs_for_display = unencoded_locs.presence || encoded_locs
55
+ locs_for_display.map(&:to_s).compact_blank.uniq
56
+ end
57
+
58
+ # Dates associated with this event as a single string.
59
+ # @return [String]
60
+ def date_str
61
+ Utils.compact_and_join(display_dates.map(&:to_s), delimiter: "; ")
62
+ end
63
+
64
+ # Edition notes associated with the event as a single string.
65
+ # @return [String]
66
+ def edition_note_str
67
+ Utils.compact_and_join(notes.filter { |note| note.type == "edition" }.map(&:to_s), delimiter: ", ")
68
+ end
69
+
70
+ # Copyright notes associated with the event as a single string.
71
+ # @return [String]
72
+ def copyright_note_str
73
+ Utils.compact_and_join(notes.filter { |note| note.type == "copyright statement" }.map(&:to_s), delimiter: ", ")
74
+ end
75
+
76
+ # All contributors associated with the event as a single string.
77
+ # @return [String]
78
+ def contributor_str
79
+ Utils.compact_and_join(contributors.map(&:display_name), delimiter: " : ")
80
+ end
81
+
82
+ # The place of publication, combining all location values.
83
+ # @return [String]
84
+ def place_str
85
+ Utils.compact_and_join(display_locations, delimiter: " : ")
86
+ end
87
+ end
88
+ end
89
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  # :nodoc:
4
4
  module CocinaDisplay
5
- VERSION = "2.0.0" # :nodoc:
5
+ VERSION = "2.1.0" # :nodoc:
6
6
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cocina_display
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Budak
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-03-25 00:00:00.000000000 Z
10
+ date: 2026-03-26 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: janeway-jsonpath
@@ -269,6 +269,7 @@ files:
269
269
  - lib/cocina_display/description/url.rb
270
270
  - lib/cocina_display/display_data.rb
271
271
  - lib/cocina_display/events/event.rb
272
+ - lib/cocina_display/events/imprint.rb
272
273
  - lib/cocina_display/events/location.rb
273
274
  - lib/cocina_display/events/note.rb
274
275
  - lib/cocina_display/forms/form.rb