cocina_display 0.2.0 → 0.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/README.md +5 -11
- data/lib/cocina_display/cocina_record.rb +20 -78
- data/lib/cocina_display/concerns/contributors.rb +94 -0
- data/lib/cocina_display/concerns/events.rb +137 -0
- data/lib/cocina_display/concerns/identifiers.rb +60 -0
- data/lib/cocina_display/concerns/titles.rb +64 -0
- data/lib/cocina_display/contributor.rb +179 -0
- data/lib/cocina_display/dates/date.rb +688 -0
- data/lib/cocina_display/dates/date_range.rb +122 -0
- data/lib/cocina_display/imprint.rb +123 -0
- data/lib/cocina_display/marc_country_codes.rb +394 -0
- data/lib/cocina_display/title_builder.rb +27 -7
- data/lib/cocina_display/utils.rb +33 -0
- data/lib/cocina_display/version.rb +1 -1
- metadata +26 -2
@@ -0,0 +1,179 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support"
|
4
|
+
require "active_support/core_ext/object/blank"
|
5
|
+
require "active_support/core_ext/array/conversions"
|
6
|
+
|
7
|
+
require_relative "utils"
|
8
|
+
|
9
|
+
module CocinaDisplay
|
10
|
+
# A contributor to a work, such as an author or publisher.
|
11
|
+
class Contributor
|
12
|
+
attr_reader :cocina
|
13
|
+
|
14
|
+
# Initialize a Contributor object with Cocina structured data.
|
15
|
+
# @param cocina [Hash] The Cocina structured data for the contributor.
|
16
|
+
def initialize(cocina)
|
17
|
+
@cocina = cocina
|
18
|
+
end
|
19
|
+
|
20
|
+
# String representation of the contributor, including name and role.
|
21
|
+
# Used for debugging and logging.
|
22
|
+
# @return [String]
|
23
|
+
def to_s
|
24
|
+
Utils.compact_and_join([display_name, display_role], delimiter: ": ")
|
25
|
+
end
|
26
|
+
|
27
|
+
# Is this contributor a human?
|
28
|
+
# @return [Boolean]
|
29
|
+
def person?
|
30
|
+
cocina["type"] == "person"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Is this contributor an organization?
|
34
|
+
# @return [Boolean]
|
35
|
+
def organization?
|
36
|
+
cocina["type"] == "organization"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Is this contributor a conference?
|
40
|
+
# @return [Boolean]
|
41
|
+
def conference?
|
42
|
+
cocina["type"] == "conference"
|
43
|
+
end
|
44
|
+
|
45
|
+
# Is this contributor marked as primary?
|
46
|
+
# @return [Boolean]
|
47
|
+
def primary?
|
48
|
+
cocina["status"] == "primary"
|
49
|
+
end
|
50
|
+
|
51
|
+
# Does this contributor have a role that indicates they are an author?
|
52
|
+
# @return [Boolean]
|
53
|
+
def author?
|
54
|
+
roles.any? { |role| role["value"] =~ /(author|creator)/i }
|
55
|
+
end
|
56
|
+
|
57
|
+
# Does this contributor have any roles defined?
|
58
|
+
# @return [Boolean]
|
59
|
+
def role?
|
60
|
+
roles.any?
|
61
|
+
end
|
62
|
+
|
63
|
+
# The display name for the contributor as a string.
|
64
|
+
# Uses the first name if multiple names are present.
|
65
|
+
# @param with_date [Boolean] Include life dates, if present
|
66
|
+
# @return [String]
|
67
|
+
def display_name(with_date: false)
|
68
|
+
names.map { |name| name.display_str(with_date: with_date) }.first
|
69
|
+
end
|
70
|
+
|
71
|
+
# A string representation of the contributor's roles, formatted for display.
|
72
|
+
# If there are multiple roles, they are joined with commas.
|
73
|
+
# @return [String]
|
74
|
+
def display_role
|
75
|
+
roles.map { |role| role["value"] }.to_sentence
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
# All names in the Cocina as Name objects.
|
81
|
+
# @return [Array<Name>]
|
82
|
+
def names
|
83
|
+
@names ||= Array(cocina["name"]).map { |name| Name.new(name) }
|
84
|
+
end
|
85
|
+
|
86
|
+
# All roles in the Cocina structured data.
|
87
|
+
# @return [Array<Hash>]
|
88
|
+
def roles
|
89
|
+
Array(cocina["role"])
|
90
|
+
end
|
91
|
+
|
92
|
+
# A name associated with a contributor.
|
93
|
+
class Name
|
94
|
+
attr_reader :cocina
|
95
|
+
|
96
|
+
# Initialize a Name object with Cocina structured data.
|
97
|
+
# @param cocina [Hash] The Cocina structured data for the name.
|
98
|
+
def initialize(cocina)
|
99
|
+
@cocina = cocina
|
100
|
+
end
|
101
|
+
|
102
|
+
# The display string for the name, optionally including life dates.
|
103
|
+
# @param with_date [Boolean] Include life dates, if present
|
104
|
+
# @return [String]
|
105
|
+
# @example no dates
|
106
|
+
# name.display_name # => "King, Martin Luther, Jr."
|
107
|
+
# @example with dates
|
108
|
+
# name.display_name(with_date: true) # => "King, Martin Luther, Jr., 1929-1968"
|
109
|
+
def display_str(with_date: false)
|
110
|
+
if dates_str.present? && with_date
|
111
|
+
Utils.compact_and_join([full_name_str, dates_str], delimiter: ", ")
|
112
|
+
else
|
113
|
+
full_name_str
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
# The full name as a string.
|
120
|
+
# If any names were marked as "display", prefer those.
|
121
|
+
# Otherwise, combine all name components.
|
122
|
+
# @return [String]
|
123
|
+
def full_name_str
|
124
|
+
display_name_str.presence || Utils.compact_and_join(name_components, delimiter: ", ")
|
125
|
+
end
|
126
|
+
|
127
|
+
# Flattened form of any names explicitly marked as "display name".
|
128
|
+
# @return [String]
|
129
|
+
def display_name_str
|
130
|
+
Utils.compact_and_join(Array(name_values["display"]), delimiter: ", ")
|
131
|
+
end
|
132
|
+
|
133
|
+
# List of all name components.
|
134
|
+
# If any of forename, surname, or term of address are present, those are used.
|
135
|
+
# Otherwise, fall back to any names explicitly marked as "name" or untyped.
|
136
|
+
# @return [Array<String>]
|
137
|
+
def name_components
|
138
|
+
[surname_str, forename_ordinal_str, terms_of_address_str].compact_blank.presence || Array(name_values["name"])
|
139
|
+
end
|
140
|
+
|
141
|
+
# Flatten all forenames and ordinals into a single string.
|
142
|
+
# @return [String]
|
143
|
+
def forename_ordinal_str
|
144
|
+
Utils.compact_and_join(Array(name_values["forename"]) + Array(name_values["ordinal"]), delimiter: " ")
|
145
|
+
end
|
146
|
+
|
147
|
+
# Flatten all terms of address into a single string.
|
148
|
+
# @return [String]
|
149
|
+
def terms_of_address_str
|
150
|
+
Utils.compact_and_join(Array(name_values["term of address"]), delimiter: ", ")
|
151
|
+
end
|
152
|
+
|
153
|
+
# Flatten all surnames into a single string.
|
154
|
+
# @return [String]
|
155
|
+
def surname_str
|
156
|
+
Utils.compact_and_join(Array(name_values["surname"]), delimiter: " ")
|
157
|
+
end
|
158
|
+
|
159
|
+
# Flatten all life and activity dates into a single string.
|
160
|
+
# @return [String]
|
161
|
+
def dates_str
|
162
|
+
Utils.compact_and_join(Array(name_values["life dates"]) + Array(name_values["activity dates"]), delimiter: ", ")
|
163
|
+
end
|
164
|
+
|
165
|
+
# A hash mapping destructured name types to their values.
|
166
|
+
# Name values with no type are grouped under "name".
|
167
|
+
# @return [Hash<String, Array<String>>]
|
168
|
+
# @see https://github.com/sul-dlss/cocina-models/blob/main/docs/description_types.md#contributor-name-part-types-for-structured-value
|
169
|
+
# @note Currently we do nothing with "alternative", "inverted full name", "pseudonym", and "transliteration" types.
|
170
|
+
def name_values
|
171
|
+
Utils.flatten_structured_values(cocina).each_with_object({}) do |node, hash|
|
172
|
+
type = node["type"] || "name"
|
173
|
+
hash[type] ||= []
|
174
|
+
hash[type] << node["value"]
|
175
|
+
end.compact_blank
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|