Class: PennMARC::Creator

Inherits:
Helper
  • Object
show all
Defined in:
lib/pennmarc/helpers/creator.rb

Overview

TODO:

can there ever be multiple 100 fields? can ǂe and ǂ4 both be used at the same time? seems to result in duplicate values

Do Creator & Author field processing. Main methods pull from 110 and 111 fields.

Constant Summary collapse

TAGS =

Main tags for Author/Creator information

%w[100 110].freeze
DISPLAY_EXCLUDED_SUBFIELDS =

For creator fields intended for display, these subfields are ignored

%w[a 0 1 4 5 6 8 t].freeze
SEARCH_EXCLUDED_SUBFIELDS =

For creator fields intended for searching, these subfields are ignored

%w[a 1 4 5 6 8 t].freeze
AUX_TAGS =

Aux tags for Author/Creator information, for use in search_aux method

%w[100 110 111 400 410 411 700 710 711 800 810 811].freeze
CONFERENCE_SEARCH_TAGS =
%w[111 711 811].freeze
CORPORATE_SEARCH_TAGS =
%w[110 710 810].freeze
CONTRIBUTOR_TAGS =
%w[700 710].freeze
CONTRIBUTOR_DISPLAY_SUBFIELDS =
%w[a b c d j q u 3].freeze
FACET_SOURCE_MAP =
{
  100 => 'abcdjq', 110 => 'abcdjq', 111 => 'abcen',
  700 => 'abcdjq', 710 => 'abcdjq', 711 => 'abcen',
  800 => 'abcdjq', 810 => 'abcdjq', 811 => 'abcen'
}.freeze

Constants included from Util

Util::TRAILING_PUNCTUATIONS_PATTERNS

Class Method Summary collapse

Methods included from Util

#append_relator, #append_trailing, #datafield_and_linked_alternate, #field_defined?, #field_or_its_linked_alternate?, #join_and_squish, #join_subfields, #linked_alternate, #linked_alternate_not_6_or_8, #no_subfield_value_matches?, #prefixed_subject_and_alternate, #relator, #relator_join_separator, #relator_term_subfield, #remove_paren_value_from_subfield_i, #subfield_defined?, #subfield_in?, #subfield_not_in?, #subfield_undefined?, #subfield_value?, #subfield_value_in?, #subfield_value_not_in?, #subfield_values, #subfield_values_for, #substring_after, #substring_before, #translate_relator, #trim_punctuation, #trim_trailing, #trim_trailing!, #valid_subject_genre_source_code?

Class Method Details

.authors_list(record, main_tags_only: false, first_initial_only: false) ⇒ Array<String>

Returns the list of authors with name (subfield $a) only

Parameters:

  • record (MARC::Record)
  • main_tags_only (Boolean) (defaults to: false) —

    only use TAGS; otherwise use both TAGS and CONTRIBUTOR_TAGS

  • first_initial_only (Boolean) (defaults to: false) —

    only use the first initial instead of first name

Returns:

  • (Array<String>) —

    names of the authors



127
128
129
130
131
132
133
134
135
# File 'lib/pennmarc/helpers/creator.rb', line 127

def authors_list(record, main_tags_only: false, first_initial_only: false)
  fields = record.fields(main_tags_only ? TAGS : TAGS + CONTRIBUTOR_TAGS)
  fields.filter_map { |field|
    if field['a'].present?
      name = trim_trailing(:comma, field['a'])
      first_initial_only ? abbreviate_name(name) : name
    end
  }.uniq
end

.conference_detail_show(record, relator_map: Mappers.relator) ⇒ Array<String>

TODO:

what is ǂi for?

Note:

ported from get_conference_values

Conference detailed display, intended for record show page. Retrieve conference values for record display from 111, 711 , and their linked 880s. If there is no $i, we join subfield $i we join subfield values other than $0, $4, $5, $6, $8, $e, $j, and $w. to create the conference value. We then join the conference subunit value using subfields $e and $w. We append any relators, preferring those defined in $4 and using $j as a fallback.

Parameters:

  • record (MARC::Record)
  • relator_map (Hash) (defaults to: Mappers.relator)

Returns:

  • (Array<String>) —

    array of conference values



239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/pennmarc/helpers/creator.rb', line 239

def conference_detail_show(record, relator_map: Mappers.relator)
  conferences = record.fields(%w[111 711]).filter_map do |field|
    next unless field.indicator2.in? ['', ' ']

    parse_conference_detail_show_value(field, relator_map: relator_map)
  end
  conferences += record.fields('880').filter_map do |field|
    next unless subfield_value? field, '6', /^(111|711)/

    next if subfield_defined? field, 'i'

    conf = join_subfields(field, &subfield_not_in?(%w[0 4 5 6 8 e j w]))
    sub_unit = join_subfields(field, &subfield_in?(%w[e w]))
    conf = [conf, sub_unit].compact_blank.join(' ')

    append_relator(field: field, joined_subfields: conf, relator_term_sf: 'j', relator_map: relator_map)
  end
  conferences.uniq
end

.conference_detail_show_facet_map(record, relator_map: Mappers.relator) ⇒ Hash

Return hash of detailed conference values mapped to their corresponding facets from fields 111 and 711. Does not include linked 880s.

Parameters:

  • record (MARC::Record)
  • relator_map (Hash) (defaults to: Mappers.relator)

Returns:

  • (Hash)


265
266
267
268
269
270
271
272
273
274
275
# File 'lib/pennmarc/helpers/creator.rb', line 265

def conference_detail_show_facet_map(record, relator_map: Mappers.relator)
  conferences = record.fields(%w[111 711]).filter_map do |field|
    next unless field.indicator2.in? ['', ' ']

    show = parse_conference_detail_show_value(field, relator_map: relator_map)
    facet = parse_facet_value(field, FACET_SOURCE_MAP[field.tag.to_i].chars)
    { show: show, facet: facet }
  end

  conferences.to_h { |conf| [conf[:show], conf[:facet]] }
end

.conference_search(record) ⇒ Array<String>

Conference name values for searching

Parameters:

  • record (MARC::Record)

Returns:

  • (Array<String>)


280
281
282
283
284
# File 'lib/pennmarc/helpers/creator.rb', line 280

def conference_search(record)
  record.fields(CONFERENCE_SEARCH_TAGS).filter_map { |field|
    join_subfields(field, &subfield_in?(%w[a c d e]))
  }.uniq
end

.conference_show(record, relator_map: Mappers.relator) ⇒ Array<String>

Note:

ported from get_conference_values

Conference for display, intended for results display

Parameters:

  • record (MARC::Record)
  • relator_map (Hash) (defaults to: Mappers.relator)

Returns:

  • (Array<String>) —

    array of conference values



223
224
225
226
227
# File 'lib/pennmarc/helpers/creator.rb', line 223

def conference_show(record, relator_map: Mappers.relator)
  record.fields('111').filter_map { |field|
    name_from_main_entry field, relator_map
  }.uniq
end

.contributor_noauthor_show(record, relator_map: Mappers.relator, name_only: false, vernacular: true) ⇒ Array<String>

Similar to contributor_show, excluding the authors included in extended_show

Parameters:

  • record (MARC::Record)
  • relator_map (Hash) (defaults to: Mappers.relator)
  • name_only (Boolean) (defaults to: false)
  • vernacular (Boolean) (defaults to: true)

Returns:

  • (Array<String>)


327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
# File 'lib/pennmarc/helpers/creator.rb', line 327

def contributor_noauthor_show(record, relator_map: Mappers.relator, name_only: false, vernacular: true)
  contributor_fields = record.fields(CONTRIBUTOR_TAGS)

  # Exclude the 700 authors and collect their linkages
  excluded_linkages = []
  filtered_fields = contributor_fields.reject do |f|
    is_author = f.tag == '700' && (f['4']&.downcase == 'aut' || f['e']&.downcase&.start_with?('author'))
    excluded_linkages << "700-#{f['6'].split('-').last}" if is_author && f['6']
    is_author
  end

  # Add vernacular fields that are not excluded by checking the linkages
  if vernacular
    vernacular_fields = record.fields('880').select do |f|
      CONTRIBUTOR_TAGS.any? { |tag| f['6']&.start_with?(tag) } && !excluded_linkages.include?(f['6'])
    end
    filtered_fields.concat(vernacular_fields)
  end

  sf = name_only ? %w[a] : CONTRIBUTOR_DISPLAY_SUBFIELDS

  filtered_fields.filter_map { |field|
    next if ['', ' ', '0'].exclude?(field.indicator2) && field.tag.in?(CONTRIBUTOR_TAGS)
    next if subfield_defined? field, 'i'

    contributor = join_subfields(field, &subfield_in?(sf))
    append_relator(field: field, joined_subfields: contributor, relator_term_sf: 'e', relator_map: relator_map)
  }.uniq
end

.contributor_show(record, relator_map: Mappers.relator, name_only: false, vernacular: true) ⇒ Array<String>

Note:

legacy version returns array of hash objects including data for display link

Retrieve contributor values for display from fields 700 and 710 and their linked alternates. Joins subfields defined in CONTRIBUTOR_DISPLAY_SUBFIELDS, then appends resulting string with any encoded relationships found in $4. If there are no valid encoded relationships, uses the value found in $e.

Parameters:

  • record (MARC::Record)
  • relator_map (Hash) (defaults to: Mappers.relator)
  • name_only (Boolean) (defaults to: false)
  • vernacular (Boolean) (defaults to: true)

Returns:

  • (Array<String>)


305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
# File 'lib/pennmarc/helpers/creator.rb', line 305

def contributor_show(record, relator_map: Mappers.relator, name_only: false, vernacular: true)
  indicator_2_options = ['', ' ', '0']
  fields = record.fields(CONTRIBUTOR_TAGS)
  if vernacular
    fields += record.fields('880').select { |f| subfield_value?(f, '6', /^(#{CONTRIBUTOR_TAGS.join('|')})/) }
  end
  sf = name_only ? %w[a] : CONTRIBUTOR_DISPLAY_SUBFIELDS
  fields.filter_map { |field|
    next if indicator_2_options.exclude?(field.indicator2) && field.tag.in?(CONTRIBUTOR_TAGS)
    next if subfield_defined? field, 'i'

    contributor = join_subfields(field, &subfield_in?(sf))
    append_relator(field: field, joined_subfields: contributor, relator_term_sf: 'e', relator_map: relator_map)
  }.uniq
end

.contributors_list(record, relator_map: Mappers.relator, include_authors: true, name_only: true, vernacular: false) ⇒ Hash

Show the authors and contributors grouped together by relators with only names

Parameters:

  • record (MARC::Record)
  • relator_map (Hash) (defaults to: Mappers.relator)
  • include_authors (Boolean) (defaults to: true) —

    include author fields TAGS

  • name_only (Boolean) (defaults to: true) —

    include only the name subfield $a

  • vernacular (Boolean) (defaults to: false) —

    include field 880 with subfield $6

Returns:

  • (Hash)


144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/pennmarc/helpers/creator.rb', line 144

def contributors_list(record, relator_map: Mappers.relator, include_authors: true, name_only: true,
                      vernacular: false)
  indicator_2_options = ['', ' ', '0']
  tags = CONTRIBUTOR_TAGS

  fields = record.fields(tags)
  fields += record.fields('880').select { |field| subfield_value_in?(field, '6', CONTRIBUTOR_TAGS) } if vernacular

  contributors = {}
  fields.each do |field|
    next if indicator_2_options.exclude?(field.indicator2) && field.tag.in?(CONTRIBUTOR_TAGS)
    next if subfield_defined? field, 'i'

    relator = relator(field: field, relator_term_sf: 'e', relator_map: relator_map)
    relator = 'Contributor' if relator.blank?
    relator = trim_punctuation(relator).capitalize

    name = trim_trailing(:comma, field['a'])
    name = "#{name} #{join_subfields(field, &subfield_in?(%w[b c d j q u 3]))}, #{relator}" unless name_only

    if contributors.key?(relator)
      contributors[relator].push(name)
    else
      contributors[relator] = [name]
    end
  end

  # add the authors
  if include_authors
    authors = authors_list(record, main_tags_only: true)
    if contributors.key?('Author')
      contributors['Author'] += authors
    else
      contributors['Author'] = authors
    end
  end
  contributors
end

.corporate_search(record) ⇒ Array<String>

Corporate author search values for searching

Parameters:

  • record (MARC::Record)

Returns:

  • (Array<String>)


289
290
291
292
293
# File 'lib/pennmarc/helpers/creator.rb', line 289

def corporate_search(record)
  record.fields(CORPORATE_SEARCH_TAGS).filter_map do |field|
    join_subfields(field, &subfield_in?(%w[a b c d]))
  end
end

.extended_show(record, relator_map: Mappers.relator) ⇒ Array<String>

Show more credited authors - both 100 field and 700 entries where the relator (codes e or 4) is author/aut

Parameters:

  • record (MARC::Record)
  • relator_map (Hash) (defaults to: Mappers.relator)

Returns:

  • (Array<String>) —

    array of author/creator values for display



94
95
96
97
98
99
100
101
102
103
# File 'lib/pennmarc/helpers/creator.rb', line 94

def extended_show(record, relator_map: Mappers.relator)
  fields = record.fields(TAGS + %w[700 710])
  fields += record.fields('880').select { |field| subfield_value?(field, '6', /^(#{TAGS.join('|')})/) }
  fields.filter_map { |field|
    # for 700, 710 and 880 entries, only include ones with relator code ('4') = aut, or code 'e' = 'author'
    next if field.tag.in?(%w[700 710 880]) && !describes_author?(field)

    parse_show_value(field, relator_map: relator_map)
  }.uniq
end

.extended_show_facet_map(record, relator_map: Mappers.relator) ⇒ Hash

Hash with extended creators show values as the fields and the corresponding facet as the values. Only include 100, and 700 with relator (codes e or 4) of author/aut

Parameters:

  • record (MARC::Record)
  • relator_map (Hash) (defaults to: Mappers.relator)

Returns:

  • (Hash)


110
111
112
113
114
115
116
117
118
119
120
# File 'lib/pennmarc/helpers/creator.rb', line 110

def extended_show_facet_map(record, relator_map: Mappers.relator)
  creators = record.fields(%w[100 700]).filter_map do |field|
    # for 700 entries, only include ones with relator code ('4') = aut, or code 'e' = 'author'
    next if field.tag == '700' && !describes_author?(field)

    show = parse_show_value(field, relator_map: relator_map)
    facet = parse_facet_value(field, FACET_SOURCE_MAP[field.tag.to_i].chars)
    { show: show, facet: facet }
  end
  creators.to_h { |h| [h[:show], h[:facet]] }
end

.facet(record) ⇒ Array<String>

TODO:

should trim_punctuation apply to each subfield value, or the joined values? i think the joined values

Author/Creator for faceting. Grabs values from a plethora of fields, joins defined subfields, then trims some punctuation (@see Util.trim_punctuation)

Parameters:

  • record (MARC::Record)

Returns:

  • (Array<String>) —

    array of author/creator values for faceting



210
211
212
213
214
215
216
# File 'lib/pennmarc/helpers/creator.rb', line 210

def facet(record)
  FACET_SOURCE_MAP.flat_map { |field_num, subfields|
    record.fields(field_num.to_s).map do |field|
      parse_facet_value(field, subfields.chars)
    end
  }.uniq
end

.search(record, relator_map: Mappers.relator) ⇒ Array<String>

Author/Creator search field, from tags 100 Main Entry--Personal Name and 110 Main Entry--Corporate Name. Includes subfield values except for those in the DISPLAY_EXCLUDED_SUBFIELDS constant. Maps any relator codes found in ǂ4. To better handle name searches, returns names as both "First Last" and "Last, First" if a comma is found in ǂa. Also indexes any linked values in the 880.

Parameters:

  • record (MARC::Record)
  • relator_map (Hash) (defaults to: Mappers.relator)

Returns:

  • (Array<String>) —

    array of author/creator values for indexing



42
43
44
# File 'lib/pennmarc/helpers/creator.rb', line 42

def search(record, relator_map: Mappers.relator)
  name_search_values record: record, tags: TAGS, relator_map: relator_map
end

.search_aux(record, relator_map: Mappers.relator) ⇒ Array<String>

Auxiliary Author/Creator search field This duplicates the values returned by the search method, but adds in additional MARC tags to include creator-adjacent entities. The added 4xx tags are mostly obsolete, but the 7xx tags are important. See: MARC 700, MARC 710, and MARC 711. The 800, 810 and 8111 tags are similar in theme to the 7xx fields but apply to serial records. Includes all subfield values except those in the SEARCH_EXCLUDED_SUBFIELDS constant.

Parameters:

  • record (MARC::Record)
  • relator_map (Hash) (defaults to: Mappers.relator)

Returns:

  • (Array<String>) —

    array of extended author/creator values for indexing



57
58
59
# File 'lib/pennmarc/helpers/creator.rb', line 57

def search_aux(record, relator_map: Mappers.relator)
  name_search_values record: record, tags: AUX_TAGS, relator_map: relator_map
end

.show(record, relator_map: Mappers.relator) ⇒ Array<String>

Retrieve creator values for display from fields 100, 110 and their linked alternates. First, join each subfield value except for those defined in the DISPLAY_EXCLUDED_SUBFIELDS constant. Then, appends any encoded relators found in $4. If there are no valid encoded relators, uses the value found in $e.

Parameters:

  • record (MARC::Record)
  • relator_map (Hash) (defaults to: Mappers.relator)

Returns:

  • (Array<String>) —

    array of author/creator values for display



68
69
70
71
72
73
74
# File 'lib/pennmarc/helpers/creator.rb', line 68

def show(record, relator_map: Mappers.relator)
  fields = record.fields(TAGS)
  fields += record.fields('880').select { |field| subfield_value?(field, '6', /^(#{TAGS.join('|')})/) }
  fields.filter_map { |field|
    parse_show_value(field, relator_map: relator_map)
  }.uniq
end

.show_aux(record, relator_map: Mappers.relator) ⇒ Array<String>

Note:

ported from get_author_creator_values (indexed as author_creator_a) - shown on results page

All author/creator values for display (like #show, but multivalued?) - no 880 linkage Performs additional normalization of author names

Parameters:

  • record (MARC::Record)
  • relator_map (Hash) (defaults to: Mappers.relator)

Returns:

  • (Array<String>) —

    array of author/creator values for display



189
190
191
192
193
# File 'lib/pennmarc/helpers/creator.rb', line 189

def show_aux(record, relator_map: Mappers.relator)
  record.fields(TAGS).map { |field|
    name_from_main_entry(field, relator_map)
  }.uniq
end

.show_facet_map(record, relator_map: Mappers.relator) ⇒ Hash

Hash with main creator show values as the fields and the corresponding facet as the values. Does not include linked 880s.

Parameters:

  • record (MARC::Record)
  • relator_map (Hash) (defaults to: Mappers.relator)

Returns:

  • (Hash)


81
82
83
84
85
86
87
88
# File 'lib/pennmarc/helpers/creator.rb', line 81

def show_facet_map(record, relator_map: Mappers.relator)
  creators = record.fields(TAGS).filter_map do |field|
    show = parse_show_value(field, relator_map: relator_map)
    facet = parse_facet_value(field, FACET_SOURCE_MAP[field.tag.to_i].chars)
    { show: show, facet: facet }
  end
  creators.to_h { |h| [h[:show], h[:facet]] }
end

.sort(record) ⇒ String

TODO:

This includes any URI from ǂ0 which could help to disambiguate in sorts, but ǂ1 is excluded...

Note:

ported from get_author_creator_sort_values

Author/Creator sort. Does not map or include any relator codes.

Parameters:

  • record (MARC::Record)

Returns:

  • (String) —

    string with author/creator value for sorting



200
201
202
203
# File 'lib/pennmarc/helpers/creator.rb', line 200

def sort(record)
  field = record.fields(TAGS).first
  join_subfields(field, &subfield_not_in?(%w[1 4 6 8 e]))
end