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. Display methods here no longer return data structures intended for generating “search” links, but some of the split subfield parsing remains from ported methods in case we need to replicate that functionality.

Constant Summary collapse

TAGS =

Main tags for Author/Creator information

%w[100 110].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
NAME_EXCLUDED_SUBFIELDS =

subfields NOT to join when combining raw subfield values

%w[a 1 4 5 6 8 t].freeze
CONTRIBUTOR_TAGS =
%w[700 710].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



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

def authors_list(record, main_tags_only: false, first_initial_only: false)
  tags = if main_tags_only
           TAGS
         else
           TAGS + CONTRIBUTOR_TAGS
         end

  fields = record.fields(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)

Returns:

  • (Array<String>)

    array of conference values



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/pennmarc/helpers/creator.rb', line 216

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)


242
243
244
245
246
247
248
249
250
251
252
# File 'lib/pennmarc/helpers/creator.rb', line 242

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>)


257
258
259
260
261
# File 'lib/pennmarc/helpers/creator.rb', line 257

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



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

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

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

TODO:

is it okay to include 880 $4 here? Legacy includes $4 in main author display 880 but not here.

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 ‘a’, ‘b’, ‘c’, ‘d’, ‘j’, and ‘q’, ‘u’, and ‘3’. 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)

Returns:

  • (Array<String>)


281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/pennmarc/helpers/creator.rb', line 281

def contributor_show(record, relator_map: Mappers.relator)
  indicator_2_options = ['', ' ', '0']
  fields = record.fields(CONTRIBUTOR_TAGS)
  fields += record.fields('880').select { |f| subfield_value?(f, '6', /^(#{CONTRIBUTOR_TAGS.join('|')})/) }
  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?(%w[a b c d j q u 3]))
    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)


116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/pennmarc/helpers/creator.rb', line 116

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 = if name_only
             name
           else
             "#{name} #{join_subfields(field, &subfield_in?(%w[b c d j q u 3]))}, #{relator}"
           end

    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>)


266
267
268
269
270
# File 'lib/pennmarc/helpers/creator.rb', line 266

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

.facet(record) ⇒ Array<String>

TODO:

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

Note:

ported from author_creator_xfacet2_input - is this the best choice? check the copyField declarations - franklin uses author_creator_f

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



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

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>

TODO:

are we including too many details here and gumming up our index? consider UIRs, relator labels, dates…

TODO:

shouldn’t indicator1 tell us the order of the name? do we not trust the indicator?

Note:

ported from get_author_creator_1_search_values

Author/Creator search field. Includes all subfield values (even ǂ0 URIs) from 100 Main Entry–Personal Name and 110 Main Entry–Corporate Name. 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>

Note:

ported from get_author_creator_2_search_values

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.

Parameters:

  • record (MARC::Record)

Returns:

  • (Array<String>)

    array of extended author/creator values for indexing



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

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 and 110 and their linked alternates. First, joins subfields other than $0, $1, $4, $6, $8, $e, and w. 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)

Returns:

  • (Array<String>)

    array of author/creator values for display



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

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



165
166
167
168
169
# File 'lib/pennmarc/helpers/creator.rb', line 165

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)


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

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 and include any relator codes.

Parameters:

  • record (MARC::Record)

Returns:

  • (String)

    string with author/creator value for sorting



176
177
178
179
# File 'lib/pennmarc/helpers/creator.rb', line 176

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