pennmarc 1.0.25 → 1.0.27

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +8 -9
  3. data/Gemfile +1 -0
  4. data/Gemfile.lock +2 -0
  5. data/README.md +16 -1
  6. data/lib/pennmarc/heading_control.rb +22 -4
  7. data/lib/pennmarc/helpers/creator.rb +139 -65
  8. data/lib/pennmarc/helpers/edition.rb +5 -3
  9. data/lib/pennmarc/helpers/note.rb +24 -19
  10. data/lib/pennmarc/helpers/production.rb +113 -20
  11. data/lib/pennmarc/helpers/subject.rb +32 -22
  12. data/lib/pennmarc/mappers.rb +22 -10
  13. data/lib/pennmarc/mappings/headings_override.yml +8 -0
  14. data/lib/pennmarc/mappings/headings_remove.yml +2 -0
  15. data/lib/pennmarc/test/marc_helpers.rb +83 -0
  16. data/lib/pennmarc/util.rb +98 -69
  17. data/lib/pennmarc/version.rb +1 -1
  18. data/lib/pennmarc.rb +7 -0
  19. data/pennmarc.gemspec +2 -1
  20. data/spec/lib/pennmarc/heading_control_spec.rb +45 -0
  21. data/spec/lib/pennmarc/helpers/access_spec.rb +0 -2
  22. data/spec/lib/pennmarc/helpers/citation_spec.rb +0 -2
  23. data/spec/lib/pennmarc/helpers/classification_spec.rb +0 -2
  24. data/spec/lib/pennmarc/helpers/creator_spec.rb +103 -2
  25. data/spec/lib/pennmarc/helpers/database_spec.rb +0 -2
  26. data/spec/lib/pennmarc/helpers/date_spec.rb +0 -2
  27. data/spec/lib/pennmarc/helpers/edition_spec.rb +4 -2
  28. data/spec/lib/pennmarc/helpers/format_spec.rb +0 -2
  29. data/spec/lib/pennmarc/helpers/genre_spec.rb +0 -2
  30. data/spec/lib/pennmarc/helpers/identifer_spec.rb +0 -2
  31. data/spec/lib/pennmarc/helpers/inventory_spec.rb +0 -2
  32. data/spec/lib/pennmarc/helpers/language_spec.rb +0 -2
  33. data/spec/lib/pennmarc/helpers/link_spec.rb +0 -2
  34. data/spec/lib/pennmarc/helpers/location_spec.rb +0 -2
  35. data/spec/lib/pennmarc/helpers/note_spec.rb +22 -29
  36. data/spec/lib/pennmarc/helpers/production_spec.rb +121 -22
  37. data/spec/lib/pennmarc/helpers/relation_spec.rb +0 -2
  38. data/spec/lib/pennmarc/helpers/series_spec.rb +0 -2
  39. data/spec/lib/pennmarc/helpers/subject_spec.rb +19 -2
  40. data/spec/lib/pennmarc/helpers/title_spec.rb +0 -2
  41. data/spec/lib/pennmarc/marc_util_spec.rb +0 -2
  42. data/spec/lib/pennmarc/parser_spec.rb +1 -1
  43. data/spec/spec_helper.rb +7 -0
  44. data/spec/support/fixture_helpers.rb +10 -0
  45. metadata +23 -3
  46. data/spec/support/marc_spec_helpers.rb +0 -85
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b540ecd84333f097b50a3682732229854b188fcde76921eb0ec184622a690dd
4
- data.tar.gz: 9203fadee45b9ad65ec20880a1acbc23356000b748d32d07428ec093590cd55a
3
+ metadata.gz: a6dec6a3d235117c15b3a37f368533a93e30ce4dfb11ac4832a612f878e653d9
4
+ data.tar.gz: 4217da9f4a2126e46284c48f4aeaca09016f4abf6ce08c493e039dae20b4bc20
5
5
  SHA512:
6
- metadata.gz: 6770815e8f5f828c15451fc71c04dbef6a131203e8c58d721c063b15f218d5814a71b37fd6c4f088a9c7164d5d989ff6933abc820094068921f218c937a87410
7
- data.tar.gz: 94eee63c29ae06151816a532a5afb7db1f27490de798651c909dc07fd0f33de1b4a1ee26057b6e3a8abc5d15c54d09709df8942e6e21ad828c1296fe3191725e
6
+ metadata.gz: 8f3f0163eb6c3b2afeb8bd8845762c1c208bbbb9efb586e3978f5f5584f73159adb2649a801d78c090e6349c72f69197b1e721acd3bdbe3a79e9f99ac11f23ee
7
+ data.tar.gz: d4595b310f8a7b765a16738799b642fc05f680b681d4e090bca11a903ca7b748a25ca0981a260290c8544faea91b9437f7b98358f5358551e787dc0ae9ab8531
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 10000`
3
- # on 2024-01-17 17:00:02 UTC using RuboCop version 1.51.0.
3
+ # on 2024-07-02 15:41:46 UTC using RuboCop version 1.51.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -14,7 +14,7 @@ Gemspec/RequireMFA:
14
14
  Exclude:
15
15
  - 'pennmarc.gemspec'
16
16
 
17
- # Offense count: 23
17
+ # Offense count: 25
18
18
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
19
19
  Metrics/AbcSize:
20
20
  Exclude:
@@ -26,18 +26,18 @@ Metrics/AbcSize:
26
26
  - 'lib/pennmarc/helpers/location.rb'
27
27
  - 'lib/pennmarc/helpers/note.rb'
28
28
  - 'lib/pennmarc/helpers/production.rb'
29
- - 'lib/pennmarc/helpers/relation.rb'
30
29
  - 'lib/pennmarc/helpers/series.rb'
31
30
  - 'lib/pennmarc/helpers/subject.rb'
32
31
  - 'lib/pennmarc/helpers/title.rb'
33
32
  - 'lib/pennmarc/util.rb'
34
33
 
35
- # Offense count: 5
34
+ # Offense count: 8
36
35
  # Configuration parameters: CountComments, Max, CountAsOne.
37
36
  Metrics/ClassLength:
38
37
  Exclude:
39
38
  - 'lib/pennmarc/helpers/creator.rb'
40
39
  - 'lib/pennmarc/helpers/format.rb'
40
+ - 'lib/pennmarc/helpers/production.rb'
41
41
  - 'lib/pennmarc/helpers/series.rb'
42
42
  - 'lib/pennmarc/helpers/subject.rb'
43
43
  - 'lib/pennmarc/helpers/title.rb'
@@ -54,13 +54,12 @@ Metrics/CyclomaticComplexity:
54
54
  - 'lib/pennmarc/helpers/language.rb'
55
55
  - 'lib/pennmarc/helpers/note.rb'
56
56
  - 'lib/pennmarc/helpers/production.rb'
57
- - 'lib/pennmarc/helpers/relation.rb'
58
57
  - 'lib/pennmarc/helpers/series.rb'
59
58
  - 'lib/pennmarc/helpers/subject.rb'
60
59
  - 'lib/pennmarc/helpers/title.rb'
61
60
  - 'lib/pennmarc/util.rb'
62
61
 
63
- # Offense count: 26
62
+ # Offense count: 28
64
63
  # Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns.
65
64
  Metrics/MethodLength:
66
65
  Exclude:
@@ -82,7 +81,7 @@ Metrics/ModuleLength:
82
81
  Exclude:
83
82
  - 'lib/pennmarc/util.rb'
84
83
 
85
- # Offense count: 12
84
+ # Offense count: 14
86
85
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
87
86
  Metrics/PerceivedComplexity:
88
87
  Exclude:
@@ -123,7 +122,7 @@ Naming/VariableNumber:
123
122
  Exclude:
124
123
  - 'lib/pennmarc/util.rb'
125
124
 
126
- # Offense count: 7
125
+ # Offense count: 8
127
126
  # Configuration parameters: Max, CountAsOne.
128
127
  RSpec/ExampleLength:
129
128
  Exclude:
@@ -139,7 +138,7 @@ RSpec/FilePath:
139
138
  Exclude:
140
139
  - 'spec/lib/pennmarc/parser_spec.rb'
141
140
 
142
- # Offense count: 12
141
+ # Offense count: 23
143
142
  # Configuration parameters: Max, AllowedGroups.
144
143
  RSpec/NestedGroups:
145
144
  Exclude:
data/Gemfile CHANGED
@@ -5,6 +5,7 @@ source 'https://rubygems.org'
5
5
  gem 'activesupport', '~> 7'
6
6
  gem 'library_stdnums', '~> 1.6'
7
7
  gem 'marc', '~> 1.2'
8
+ gem 'multi_string_replace', '~> 2.0'
8
9
  gem 'nokogiri', '~> 1.15'
9
10
  gem 'rake', '~> 13.0'
10
11
  gem 'upennlib-rubocop', require: false
data/Gemfile.lock CHANGED
@@ -19,6 +19,7 @@ GEM
19
19
  scrub_rb (>= 1.0.1, < 2)
20
20
  unf
21
21
  minitest (5.18.0)
22
+ multi_string_replace (2.0.2)
22
23
  nokogiri (1.15.2-arm64-darwin)
23
24
  racc (~> 1.4)
24
25
  nokogiri (1.15.2-x64-mingw-ucrt)
@@ -113,6 +114,7 @@ DEPENDENCIES
113
114
  activesupport (~> 7)
114
115
  library_stdnums (~> 1.6)
115
116
  marc (~> 1.2)
117
+ multi_string_replace (~> 2.0)
116
118
  nokogiri (~> 1.15)
117
119
  rake (~> 13.0)
118
120
  rspec (~> 3.12)
data/README.md CHANGED
@@ -7,13 +7,28 @@ the "Nouveau Franklin" project aka [discovery_app](https://gitlab.library.upenn.
7
7
  When included in a project, it should be utilized like this:
8
8
 
9
9
  ```ruby
10
- parser = PennMARC::Parser.new # eventually we will pass in some mappings...
10
+ parser = PennMARC::Parser.new
11
11
  puts parser.title_show(marc_record) # Title intended for display
12
12
  ```
13
13
 
14
14
  All methods will require a `MARC::Record` object. For more about these, see the
15
15
  [ruby-marc](https://github.com/ruby-marc/ruby-marc) gem documentation
16
16
 
17
+ ## Term Overriding
18
+
19
+ This gem provides configuration as well as a method for overriding and removing terms that are undesirable. In your app,
20
+ you can remove or replace the configured terms like so:
21
+
22
+ ```ruby
23
+ improved_values = PennMARC::HeadingControl.term_override(values)
24
+ ```
25
+
26
+ This will remove any elements of the `values` array that include any terms defined in `mappers/headings_remove.yml` and
27
+ replace any terms defined in the `headings_override.yml` file.
28
+
29
+ By default, terms are replaced for `Subject#*show` and `Subject#facet` methods. You can bypass the default overriding on
30
+ on these methods by passing `override: false`.
31
+
17
32
  ## Development
18
33
 
19
34
  ### Requirements
@@ -1,11 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'multi_string_replace'
4
+
3
5
  module PennMARC
4
- # Shared values for controlling inclusion of subject or genre headings
5
- module HeadingControl
6
- # These codes are expected to be found in sf2 when the indicator2 value is 7, indicating "source specified". There
7
- # are some sources whose headings we don't want to display.
6
+ # Shared tools and values for controlling handling of subject or genre headings
7
+ class HeadingControl
8
+ # These codes are expected to be found in sf2 of a subject/genre field when the indicator2 value is 7, indicating
9
+ # "source specified". There are some sources whose headings we don't want to display.
8
10
  ALLOWED_SOURCE_CODES = %w[aat cct fast ftamc gmgpc gsafd homoit jlabsh lcgft lcsh lcstt lctgm
9
11
  local/osu mesh ndlsh nli nlksh rbbin rbgenr rbmscv rbpap rbpri rbprov rbpub rbtyp].freeze
12
+
13
+ class << self
14
+ # Replace or remove any terms in provided values pursuant to the configuration in remove and override mappers.
15
+ # Used to remove or replace offensive or otherwise undesirable subject headings.
16
+ # @param values [Array]
17
+ # @return [Array] values with terms removed/replaced
18
+ def term_override(values)
19
+ values.filter_map do |value|
20
+ # Remove values if they contain a remove term
21
+ next nil if value.match?(/#{Mappers.headings_to_remove&.join('|')}/i)
22
+
23
+ # Replace values using multi_string_replace gem
24
+ MultiStringReplace.replace value, Mappers.heading_overrides
25
+ end
26
+ end
27
+ end
10
28
  end
11
29
  end
@@ -7,26 +7,27 @@ module PennMARC
7
7
  # @todo can there ever be multiple 100 fields?
8
8
  # can ǂe and ǂ4 both be used at the same time? seems to result in duplicate values
9
9
  class Creator < Helper
10
- class << self
11
- # Main tags for Author/Creator information
12
- TAGS = %w[100 110].freeze
10
+ # Main tags for Author/Creator information
11
+ TAGS = %w[100 110].freeze
13
12
 
14
- # Aux tags for Author/Creator information, for use in search_aux method
15
- AUX_TAGS = %w[100 110 111 400 410 411 700 710 711 800 810 811].freeze
13
+ # Aux tags for Author/Creator information, for use in search_aux method
14
+ AUX_TAGS = %w[100 110 111 400 410 411 700 710 711 800 810 811].freeze
16
15
 
17
- CONFERENCE_SEARCH_TAGS = %w[111 711 811].freeze
16
+ CONFERENCE_SEARCH_TAGS = %w[111 711 811].freeze
17
+ CORPORATE_SEARCH_TAGS = %w[110 710 810].freeze
18
18
 
19
- # subfields NOT to join when combining raw subfield values
20
- NAME_EXCLUDED_SUBFIELDS = %w[a 1 4 5 6 8 t].freeze
19
+ # subfields NOT to join when combining raw subfield values
20
+ NAME_EXCLUDED_SUBFIELDS = %w[a 1 4 5 6 8 t].freeze
21
21
 
22
- CONTRIBUTOR_TAGS = %w[700 710].freeze
22
+ CONTRIBUTOR_TAGS = %w[700 710].freeze
23
23
 
24
- FACET_SOURCE_MAP = {
25
- 100 => 'abcdjq', 110 => 'abcdjq', 111 => 'abcen',
26
- 700 => 'abcdjq', 710 => 'abcdjq', 711 => 'abcen',
27
- 800 => 'abcdjq', 810 => 'abcdjq', 811 => 'abcen'
28
- }.freeze
24
+ FACET_SOURCE_MAP = {
25
+ 100 => 'abcdjq', 110 => 'abcdjq', 111 => 'abcen',
26
+ 700 => 'abcdjq', 710 => 'abcdjq', 711 => 'abcen',
27
+ 800 => 'abcdjq', 810 => 'abcdjq', 811 => 'abcen'
28
+ }.freeze
29
29
 
30
+ class << self
30
31
  # Author/Creator search field. Includes all subfield values (even ǂ0 URIs) from
31
32
  # {https://www.oclc.org/bibformats/en/1xx/100.html 100 Main Entry--Personal Name} and
32
33
  # {https://www.oclc.org/bibformats/en/1xx/110.html 110 Main Entry--Corporate Name}. Maps any relator codes found
@@ -35,8 +36,8 @@ module PennMARC
35
36
  # @todo are we including too many details here and gumming up our index? consider UIRs, relator labels, dates...
36
37
  # @todo shouldn't indicator1 tell us the order of the name? do we not trust the indicator?
37
38
  # @note ported from get_author_creator_1_search_values
38
- # @param [MARC::Record] record
39
- # @param [Hash] relator_map
39
+ # @param record [MARC::Record]
40
+ # @param relator_map [Hash]
40
41
  # @return [Array<String>] array of author/creator values for indexing
41
42
  def search(record, relator_map: Mappers.relator)
42
43
  name_search_values record: record, tags: TAGS, relator_map: relator_map
@@ -50,7 +51,7 @@ module PennMARC
50
51
  # and {https://www.loc.gov/marc/bibliographic/bd711.html MARC 711}. The 800, 810 and 8111 tags are similar in
51
52
  # theme to the 7xx fields but apply to serial records.
52
53
  # @note ported from get_author_creator_2_search_values
53
- # @param [MARC::Record] record
54
+ # @param record [MARC::Record]
54
55
  # @return [Array<String>] array of extended author/creator values for indexing
55
56
  def search_aux(record, relator_map: Mappers.relator)
56
57
  name_search_values record: record, tags: AUX_TAGS, relator_map: relator_map
@@ -60,7 +61,7 @@ module PennMARC
60
61
  # and {https://www.loc.gov/marc/bibliographic/bd110.html 110} and their linked alternates. First, joins subfields
61
62
  # other than $0, $1, $4, $6, $8, $e, and w. Then, appends any encoded relators found in $4.
62
63
  # If there are no valid encoded relators, uses the value found in $e.
63
- # @param [MARC::Record] record
64
+ # @param record [MARC::Record]
64
65
  # @return [Array<String>] array of author/creator values for display
65
66
  def show(record, relator_map: Mappers.relator)
66
67
  fields = record.fields(TAGS)
@@ -72,8 +73,8 @@ module PennMARC
72
73
 
73
74
  # Hash with main creator show values as the fields and the corresponding facet as the values.
74
75
  # Does not include linked 880s.
75
- # @param [MARC::Record] record
76
- # @param [Hash] relator_map
76
+ # @param record [MARC::Record]
77
+ # @param relator_map [Hash]
77
78
  # @return [Hash]
78
79
  def show_facet_map(record, relator_map: Mappers.relator)
79
80
  creators = record.fields(TAGS).filter_map do |field|
@@ -84,11 +85,82 @@ module PennMARC
84
85
  creators.to_h { |h| [h[:show], h[:facet]] }
85
86
  end
86
87
 
88
+ # Returns the list of authors with name (subfield $a) only
89
+ # @param [MARC::Record] record
90
+ # @param [Boolean] main_tags_only, if true, only use TAGS; otherwise use both TAGS and CONTRIBUTOR_TAGS
91
+ # @param [Boolean] first_initial_only: true to only use the first initial instead of first name
92
+ # @return [Array<String>] names of the authors
93
+ def authors_list(record, main_tags_only: false, first_initial_only: false)
94
+ tags = if main_tags_only
95
+ TAGS
96
+ else
97
+ TAGS + CONTRIBUTOR_TAGS
98
+ end
99
+
100
+ fields = record.fields(tags)
101
+ fields.filter_map { |field|
102
+ if first_initial_only
103
+ abbreviate_name(field['a']) if field['a']
104
+ else
105
+ field['a']
106
+ end
107
+ }.uniq
108
+ end
109
+
110
+ # Show the authors and contributors grouped together by relators with only names
111
+ # @param [MARC::Record] record
112
+ # @param [Hash] relator_map
113
+ # @param [Boolean] include_authors: true to include author fields TAGS
114
+ # @param [Boolean] name_only: true to include only the name subfield $a
115
+ # @param [Boolean] vernacular: true to include field 880 with subfield $6
116
+ # @return [Hash]
117
+ def contributors_list(record, relator_map: Mappers.relator, include_authors: true, name_only: true,
118
+ vernacular: false)
119
+ indicator_2_options = ['', ' ', '0']
120
+ tags = CONTRIBUTOR_TAGS
121
+
122
+ fields = record.fields(tags)
123
+ fields += record.fields('880').select { |field| subfield_value_in?(field, '6', CONTRIBUTOR_TAGS) } if vernacular
124
+
125
+ contributors = {}
126
+ fields.each do |field|
127
+ next if indicator_2_options.exclude?(field.indicator2) && field.tag.in?(CONTRIBUTOR_TAGS)
128
+ next if subfield_defined? field, 'i'
129
+
130
+ relator = relator(field: field, relator_term_sf: 'e', relator_map: relator_map)
131
+ relator = 'Contributor' if relator.blank?
132
+ relator = trim_punctuation(relator).capitalize
133
+
134
+ name = if name_only
135
+ field['a']
136
+ else
137
+ join_subfields(field, &subfield_in?(%w[a b c d j q u 3])) + ", #{relator}"
138
+ end
139
+
140
+ if contributors.key?(relator)
141
+ contributors[relator].push(name)
142
+ else
143
+ contributors[relator] = [name]
144
+ end
145
+ end
146
+
147
+ # add the authors
148
+ if include_authors
149
+ authors = authors_list(record, main_tags_only: true)
150
+ if contributors.key?('Author')
151
+ contributors['Author'] += authors
152
+ else
153
+ contributors['Author'] = authors
154
+ end
155
+ end
156
+ contributors
157
+ end
158
+
87
159
  # All author/creator values for display (like #show, but multivalued?) - no 880 linkage
88
160
  # Performs additional normalization of author names
89
161
  # @note ported from get_author_creator_values (indexed as author_creator_a) - shown on results page
90
- # @param [MARC::Record] record
91
- # @param [Hash] relator_map
162
+ # @param record [MARC::Record]
163
+ # @param relator_map [Hash]
92
164
  # @return [Array<String>] array of author/creator values for display
93
165
  def show_aux(record, relator_map: Mappers.relator)
94
166
  record.fields(TAGS).map { |field|
@@ -99,7 +171,7 @@ module PennMARC
99
171
  # Author/Creator sort. Does not map and include any relator codes.
100
172
  # @todo This includes any URI from ǂ0 which could help to disambiguate in sorts, but ǂ1 is excluded...
101
173
  # @note ported from get_author_creator_sort_values
102
- # @param [MARC::Record] record
174
+ # @param record [MARC::Record]
103
175
  # @return [String] string with author/creator value for sorting
104
176
  def sort(record)
105
177
  field = record.fields(TAGS).first
@@ -107,11 +179,11 @@ module PennMARC
107
179
  end
108
180
 
109
181
  # Author/Creator for faceting. Grabs values from a plethora of fields, joins defined subfields, then trims some
110
- # punctuation (@see trim_punctuation)
182
+ # punctuation (@see Util.trim_punctuation)
111
183
  # @todo should trim_punctuation apply to each subfield value, or the joined values? i think the joined values
112
184
  # @note ported from author_creator_xfacet2_input - is this the best choice? check the copyField declarations -
113
185
  # franklin uses author_creator_f
114
- # @param [MARC::Record] record
186
+ # @param record [MARC::Record]
115
187
  # @return [Array<String>] array of author/creator values for faceting
116
188
  def facet(record)
117
189
  FACET_SOURCE_MAP.flat_map { |field_num, subfields|
@@ -123,8 +195,8 @@ module PennMARC
123
195
 
124
196
  # Conference for display, intended for results display
125
197
  # @note ported from get_conference_values
126
- # @param [MARC::Record] record
127
- # @param [Hash] relator_map
198
+ # @param record [MARC::Record]
199
+ # @param relator_map [Hash]
128
200
  # @return [Array<String>] array of conference values
129
201
  def conference_show(record, relator_map: Mappers.relator)
130
202
  record.fields('111').filter_map { |field|
@@ -139,7 +211,7 @@ module PennMARC
139
211
  # using subfields $e and $w. We append any relators, preferring those defined in $4 and using $j as a fallback.
140
212
  # @note ported from get_conference_values
141
213
  # @todo what is ǂi for?
142
- # @param [MARC::Record] record
214
+ # @param record [MARC::Record]
143
215
  # @return [Array<String>] array of conference values
144
216
  def conference_detail_show(record, relator_map: Mappers.relator)
145
217
  conferences = record.fields(%w[111 711]).filter_map do |field|
@@ -164,8 +236,8 @@ module PennMARC
164
236
  # Return hash of detailed conference values mapped to their corresponding facets from fields
165
237
  # {https://www.loc.gov/marc/bibliographic/bd111.html 111} and
166
238
  # {https://www.loc.gov/marc/bibliographic/bd711.html 711}. Does not include linked 880s.
167
- # @param [MARC::Record] record
168
- # @param [Hash] relator_map
239
+ # @param record [MARC::Record]
240
+ # @param relator_map [Hash]
169
241
  # @return [Hash]
170
242
  def conference_detail_show_facet_map(record, relator_map: Mappers.relator)
171
243
  conferences = record.fields(%w[111 711]).filter_map do |field|
@@ -180,7 +252,7 @@ module PennMARC
180
252
  end
181
253
 
182
254
  # Conference name values for searching
183
- # @param [MARC::Record] record
255
+ # @param record [MARC::Record]
184
256
  # @return [Array<String>]
185
257
  def conference_search(record)
186
258
  record.fields(CONFERENCE_SEARCH_TAGS).filter_map { |field|
@@ -188,14 +260,23 @@ module PennMARC
188
260
  }.uniq
189
261
  end
190
262
 
263
+ # Corporate author search values for searching
264
+ # @param record [MARC::Record]
265
+ # @return [Array<String>]
266
+ def corporate_search(record)
267
+ record.fields(CORPORATE_SEARCH_TAGS).filter_map do |field|
268
+ join_subfields(field, &subfield_in?(%w[a b c d]))
269
+ end
270
+ end
271
+
191
272
  # Retrieve contributor values for display from fields {https://www.oclc.org/bibformats/en/7xx/700.html 700}
192
273
  # and {https://www.oclc.org/bibformats/en/7xx/710.html 710} and their linked alternates. Joins subfields
193
274
  # 'a', 'b', 'c', 'd', 'j', and 'q', 'u', and '3'. Then appends resulting string with any encoded relationships
194
275
  # found in $4. If there are no valid encoded relationships, uses the value found in $e.
195
276
  # @note legacy version returns array of hash objects including data for display link
196
277
  # @todo is it okay to include 880 $4 here? Legacy includes $4 in main author display 880 but not here.
197
- # @param [MARC::Record] record
198
- # @ param [Hash] relator_map
278
+ # @param record [MARC::Record]
279
+ # @param relator_map [Hash]
199
280
  # @return [Array<String>]
200
281
  def contributor_show(record, relator_map: Mappers.relator)
201
282
  indicator_2_options = ['', ' ', '0']
@@ -212,9 +293,9 @@ module PennMARC
212
293
 
213
294
  private
214
295
 
215
- # @param [MARC::Record] record
216
- # @param [Array] tags to consider
217
- # @param [Hash] relator_map
296
+ # @param record [MARC::Record]
297
+ # @param tags [Array] to consider
298
+ # @param relator_map [Hash]
218
299
  # @return [Array<String>] name values from given tags
219
300
  def name_search_values(record:, tags:, relator_map:)
220
301
  acc = record.fields(tags).filter_map do |field|
@@ -238,30 +319,10 @@ module PennMARC
238
319
  acc.uniq
239
320
  end
240
321
 
241
- # Trim punctuation method extracted from Traject macro, to ensure consistent output
242
- # @todo move to Util?
243
- # @param [String] string
244
- # @return [String] string with relevant punctuation removed
245
- def trim_punctuation(string)
246
- return string unless string
247
-
248
- string = string.sub(%r{ *[ ,/;:] *\Z}, '')
249
-
250
- # trailing period if it is preceded by at least three letters (possibly preceded and followed by whitespace)
251
- string = string.sub(/( *[[:word:]]{3,})\. *\Z/, '\1')
252
-
253
- # single square bracket characters if they are the start and/or end chars and there are no internal square
254
- # brackets.
255
- string = string.sub(/\A\[?([^\[\]]+)\]?\Z/, '\1')
256
-
257
- # trim any leading or trailing whitespace
258
- string.strip
259
- end
260
-
261
322
  # Extract the information we care about from 1xx fields, map relator codes, and use appropriate punctuation
262
- # @param [MARC::Field] field
263
- # @param [Hash] mapping
264
- # @param [Boolean] should_convert_name_order
323
+ # @param field [MARC::Field]
324
+ # @param mapping [Hash]
325
+ # @param should_convert_name_order [Boolean]
265
326
  # @return [String] joined subfield values for value from field
266
327
  def name_from_main_entry(field, mapping, should_convert_name_order: false)
267
328
  relator_term_sf = relator_term_subfield(field)
@@ -284,7 +345,7 @@ module PennMARC
284
345
  end
285
346
 
286
347
  # Convert "Lastname, First" to "First Lastname"
287
- # @param [String] name value for processing
348
+ # @param name [String] value for processing
288
349
  # @return [String]
289
350
  def convert_name_order(name)
290
351
  return name unless name.include? ','
@@ -294,17 +355,30 @@ module PennMARC
294
355
  "#{after_comma} #{before_comma}".squish
295
356
  end
296
357
 
358
+ # Convert "Lastname, First" to "Lastname, F"
359
+ # @param [String] name
360
+ def abbreviate_name(name)
361
+ name_parts = name.split(', ')
362
+ return '' if name_parts.empty?
363
+
364
+ first_name_parts = name_parts.last.split
365
+ temp_name = "#{name_parts.first}, #{first_name_parts.first[0, 1]}."
366
+ first_name_parts.shift
367
+ temp_name += " #{first_name_parts.join(' ')}" unless first_name_parts.empty?
368
+ temp_name
369
+ end
370
+
297
371
  # Parse creator facet value from given creator field and desired subfields
298
- # @param [MARC::Field] field
299
- # @param [Array<String>] subfields
372
+ # @param field [MARC::Field]
373
+ # @param subfields [Array<String>]
300
374
  # @return [String]
301
375
  def parse_facet_value(field, subfields)
302
376
  trim_punctuation(join_subfields(field, &subfield_in?(subfields)))
303
377
  end
304
378
 
305
379
  # Parse creator show value from given main creator fields (100/110).
306
- # @param [MARC::Field] field
307
- # @param [Hash] relator_map
380
+ # @param field [MARC::Field]
381
+ # @param relator_map [Hash]
308
382
  # @return [String]
309
383
  def parse_show_value(field, relator_map: Mappers.relator)
310
384
  creator = join_subfields(field, &subfield_not_in?(%w[0 1 4 6 8 e w]))
@@ -314,7 +388,7 @@ module PennMARC
314
388
  # Parse detailed conference show value from given conference field (111/711). If there is no $i, we join subfield
315
389
  # values other than $0, $4, $5, $6, $8, $e, $j, and $w to create conference value. We join subfields $e and $w to
316
390
  # determine the subunit value. We append any relators, preferring those defined in $4 and using $j as a fallback.
317
- # @param [MARC::Field] field
391
+ # @param field [MARC::Field]
318
392
  # @return [String]
319
393
  def parse_conference_detail_show_value(field, relator_map: Mappers.relator)
320
394
  conf = if subfield_undefined? field, 'i'
@@ -13,10 +13,12 @@ module PennMARC
13
13
  # https://www.loc.gov/marc/bibliographic/bd250.html
14
14
  # @param [MARC::Record] record
15
15
  # @return [Array<String>] array of editions and their alternates
16
- def show(record)
17
- editions = record.fields('250').map { |field|
16
+ def show(record, with_alternate: true)
17
+ editions = record.fields('250').map do |field|
18
18
  join_subfields(field, &subfield_not_in?(%w[6 8]))
19
- } + linked_alternate_not_6_or_8(record, '250')
19
+ end
20
+ editions += linked_alternate_not_6_or_8(record, '250') if with_alternate
21
+
20
22
  editions.uniq
21
23
  end
22
24