berkeley_library-tind 0.4.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +16 -4
  3. data/.gitignore +3 -0
  4. data/.idea/inspectionProfiles/Project_Default.xml +10 -0
  5. data/.idea/tind.iml +24 -22
  6. data/CHANGES.md +24 -0
  7. data/README.md +136 -3
  8. data/berkeley_library-tind.gemspec +2 -0
  9. data/bin/alma-multiple-tind +50 -0
  10. data/bin/alma-single-tind +48 -0
  11. data/bin/save_tind_records +80 -0
  12. data/bin/tind-marc +73 -0
  13. data/lib/berkeley_library/tind/mapping/additional_datafield_process.rb +128 -0
  14. data/lib/berkeley_library/tind/mapping/alma.rb +42 -0
  15. data/lib/berkeley_library/tind/mapping/alma_base.rb +101 -0
  16. data/lib/berkeley_library/tind/mapping/alma_multiple_tind.rb +31 -0
  17. data/lib/berkeley_library/tind/mapping/alma_single_tind.rb +28 -0
  18. data/lib/berkeley_library/tind/mapping/config.rb +44 -0
  19. data/lib/berkeley_library/tind/mapping/csv_mapper.rb +35 -0
  20. data/lib/berkeley_library/tind/mapping/csv_multiple_mapper.rb +41 -0
  21. data/lib/berkeley_library/tind/mapping/data/one_to_multiple_mapping.csv +4 -0
  22. data/lib/berkeley_library/tind/mapping/data/one_to_one_mapping.csv +39 -0
  23. data/lib/berkeley_library/tind/mapping/external_tind_field.rb +103 -0
  24. data/lib/berkeley_library/tind/mapping/field_catalog.rb +146 -0
  25. data/lib/berkeley_library/tind/mapping/field_catalog_util.rb +59 -0
  26. data/lib/berkeley_library/tind/mapping/match_tind_field.rb +77 -0
  27. data/lib/berkeley_library/tind/mapping/misc.rb +69 -0
  28. data/lib/berkeley_library/tind/mapping/multiple_rule.rb +36 -0
  29. data/lib/berkeley_library/tind/mapping/single_rule.rb +143 -0
  30. data/lib/berkeley_library/tind/mapping/tind_control_subfield.rb +59 -0
  31. data/lib/berkeley_library/tind/mapping/tind_field.rb +49 -0
  32. data/lib/berkeley_library/tind/mapping/tind_field_from_leader.rb +27 -0
  33. data/lib/berkeley_library/tind/mapping/tind_field_from_multiple_map.rb +59 -0
  34. data/lib/berkeley_library/tind/mapping/tind_field_from_single_map.rb +170 -0
  35. data/lib/berkeley_library/tind/mapping/tind_field_util.rb +112 -0
  36. data/lib/berkeley_library/tind/mapping/tind_marc.rb +134 -0
  37. data/lib/berkeley_library/tind/mapping/tind_subfield_util.rb +154 -0
  38. data/lib/berkeley_library/tind/mapping/util.rb +117 -0
  39. data/lib/berkeley_library/tind/mapping.rb +1 -0
  40. data/lib/berkeley_library/tind/marc/xml_builder.rb +70 -0
  41. data/lib/berkeley_library/tind/marc/xml_reader.rb +22 -16
  42. data/lib/berkeley_library/tind/marc/xml_writer.rb +152 -0
  43. data/lib/berkeley_library/tind/module_info.rb +1 -1
  44. data/lib/berkeley_library/util/files.rb +38 -0
  45. data/spec/berkeley_library/tind/mapping/additional_datafield_process_spec.rb +35 -0
  46. data/spec/berkeley_library/tind/mapping/alma_base_spec.rb +115 -0
  47. data/spec/berkeley_library/tind/mapping/alma_multiple_tind_spec.rb +20 -0
  48. data/spec/berkeley_library/tind/mapping/alma_single_tind_spec.rb +87 -0
  49. data/spec/berkeley_library/tind/mapping/alma_spec.rb +28 -0
  50. data/spec/berkeley_library/tind/mapping/config_spec.rb +19 -0
  51. data/spec/berkeley_library/tind/mapping/csv_mapper_spec.rb +27 -0
  52. data/spec/berkeley_library/tind/mapping/csv_multiple_mapper_spec.rb +27 -0
  53. data/spec/berkeley_library/tind/mapping/external_tind_field_spec.rb +45 -0
  54. data/spec/berkeley_library/tind/mapping/field_catalog_spec.rb +78 -0
  55. data/spec/berkeley_library/tind/mapping/field_catalog_util_spec.rb +57 -0
  56. data/spec/berkeley_library/tind/mapping/match_tind_field_spec.rb +25 -0
  57. data/spec/berkeley_library/tind/mapping/misc_spec.rb +51 -0
  58. data/spec/berkeley_library/tind/mapping/multiple_rule_spec.rb +44 -0
  59. data/spec/berkeley_library/tind/mapping/single_rule_spec.rb +52 -0
  60. data/spec/berkeley_library/tind/mapping/tind_control_subfield_spec.rb +96 -0
  61. data/spec/berkeley_library/tind/mapping/tind_field_from_leader_spec.rb +21 -0
  62. data/spec/berkeley_library/tind/mapping/tind_field_from_multiple_map_spec.rb +31 -0
  63. data/spec/berkeley_library/tind/mapping/tind_field_from_single_map_spec.rb +150 -0
  64. data/spec/berkeley_library/tind/mapping/tind_field_spec.rb +60 -0
  65. data/spec/berkeley_library/tind/mapping/tind_field_util_spec.rb +68 -0
  66. data/spec/berkeley_library/tind/mapping/tind_marc_spec.rb +88 -0
  67. data/spec/berkeley_library/tind/mapping/tind_subfield_util_spec.rb +48 -0
  68. data/spec/berkeley_library/tind/mapping/util_spec.rb +56 -0
  69. data/spec/berkeley_library/tind/marc/xml_reader_spec.rb +22 -0
  70. data/spec/berkeley_library/tind/marc/xml_writer_spec.rb +218 -0
  71. data/spec/data/issue-4.xml +157 -0
  72. data/spec/data/mapping/991032333019706532-sru.xml +216 -0
  73. data/spec/data/mapping/one_to_multiple_mapping.csv +4 -0
  74. data/spec/data/mapping/one_to_one_mapping.csv +39 -0
  75. data/spec/data/mapping/record.xml +263 -0
  76. data/spec/data/mapping/record_not_qualified.xml +36 -0
  77. data/spec/data/new-records.xml +46 -0
  78. metadata +128 -2
@@ -0,0 +1,59 @@
1
+ require 'marc'
2
+ require 'berkeley_library/tind/mapping/tind_control_subfield'
3
+
4
+ module BerkeleyLibrary
5
+ module TIND
6
+ module Mapping
7
+
8
+ class TindFieldFromMultipleMap
9
+ include CsvMultipleMapper
10
+ include Util
11
+ include TindControlSubfield
12
+
13
+ def initialize(controlfield, current_datafields)
14
+ @from_controlfield = controlfield
15
+ @current_tags = current_datafields.map(&:tag)
16
+ end
17
+
18
+ def to_datafields
19
+ datafields = []
20
+ control_rules = rules_on_controldatafield
21
+
22
+ if control_rules
23
+ control_rules.each do |rule|
24
+ df = to_datafield(rule)
25
+ datafields << df if df
26
+ end
27
+ end
28
+
29
+ datafields
30
+ end
31
+
32
+ private
33
+
34
+ # one control field may have multiple rules
35
+ def rules_on_controldatafield
36
+ tag = @from_controlfield.tag
37
+ sym = Util.tag_symbol(tag)
38
+ rules[sym]
39
+ end
40
+
41
+ # Check mapped current datafields has the pre-existed tag defined in the row (rule) of csv file
42
+ def pre_exsited_tag?(rule)
43
+ @current_tags.include? rule.pre_existed_tag.to_s
44
+ end
45
+
46
+ # get a datafield on a rule (row in csv file)
47
+ def to_datafield(rule)
48
+ return nil if pre_exsited_tag?(rule)
49
+
50
+ to_value = extract_value(rule, @from_controlfield.value)
51
+ return nil unless to_value
52
+
53
+ extracted_field(rule, to_value)
54
+ end
55
+
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,170 @@
1
+ require 'marc'
2
+ require 'berkeley_library/tind/mapping/util'
3
+ require 'berkeley_library/tind/mapping/tind_subfield_util'
4
+
5
+ # 1. datafield could be a regular alma field
6
+ # 1) data_fields_normal - using @single_rule_hash from SingleRule
7
+ # 2) data_fields_with_pre_existed_field - using @single_rule_hash from SingleRule
8
+ # 3) data_fields_with_pre_existed_subfield - using @single_rule_subfield_excluded_hash from SingleRule
9
+
10
+ # 2. data field could be an 880 alma field , below types are definded based on the tag from subfield6
11
+ # 1) data_fields_normal - using @single_rule_hash from SingleRule
12
+ # 2) data_fields_with_pre_existed_field - using @single_rule_hash from SingleRule
13
+ # 3) data_fields_with_pre_existed_subfield - using @single_rule_subfield_excluded_hash from SingleRule
14
+
15
+ # 3. map_to_tag, indicator are from mapping rule for output tindfield
16
+ # 4. subfileds are re-mapped, or combined, used as subfields for output tindfield
17
+
18
+ module BerkeleyLibrary
19
+ module TIND
20
+ module Mapping
21
+
22
+ class TindFieldFromSingleMap
23
+ include CsvMapper
24
+ include Util
25
+ include TindSubfieldUtil
26
+ include Misc
27
+
28
+ # excluding_subfield = false: mapping by rule.single_rule_hash
29
+ # excluding_subfield = true: mapping by rule.single_rule_subfield_excluded_hash
30
+ def initialize(datafield, excluding_subfield)
31
+ @from_datafield = datafield
32
+ @excluding_subfield = excluding_subfield
33
+
34
+ @is_880_field = is_880_field?(datafield)
35
+
36
+ @mapping_rule = rule
37
+ @map_to_tag = nil
38
+ @indicator = nil
39
+ @single_mapping = nil
40
+ @ready_to_mapping = ready_to_mapping?
41
+
42
+ @to_subfields = all_subfields
43
+ end
44
+
45
+ def to_datafield
46
+ return nil unless mapped?
47
+
48
+ tindfield = Util.datafield(@map_to_tag, @indicator, @to_subfields)
49
+ @is_880_field ? reversed_880_field(tindfield) : tindfield
50
+ end
51
+
52
+ private
53
+
54
+ # A referred tag from 880 subfield6 may not have a rule
55
+ # For example: 880 subfild6 pass in a value in wrong format
56
+ # In above case, rule is nil
57
+ # Get mapping parameters from rule when having a rule
58
+ def ready_to_mapping?
59
+ return false unless @mapping_rule
60
+
61
+ @map_to_tag = @mapping_rule.tag_destination
62
+ @indicator = @mapping_rule.indicator
63
+ @single_mapping = @excluding_subfield ? @mapping_rule.single_rule_subfield_excluded_hash : @mapping_rule.single_rule_hash
64
+
65
+ return false unless @map_to_tag && @indicator && !@single_mapping.empty?
66
+
67
+ true
68
+ end
69
+
70
+ def mapped?
71
+ !@to_subfields.empty?
72
+ end
73
+
74
+ # tag - regular alma field
75
+ # referred tag - got tag from subfield6 value of a 880 field
76
+ # nil rule caused by nil referred tag - eg. 880 subfild6 pass in a value in wrong format
77
+ def rule
78
+ tag = origin_mapping_tag(@from_datafield)
79
+ return nil unless tag
80
+
81
+ rules[Util.tag_symbol(tag)]
82
+ end
83
+
84
+ def all_subfields
85
+ @ready_to_mapping ? (subfields_from_single_map + subfields_from_combined_map) : []
86
+ end
87
+
88
+ # 1.subfields mapped with single rule, mapping one subfield to another subfield
89
+ # 2. one subfield is mapped to one subfield
90
+ # 3. When mutiple subfields with the same name found in an orignal field,
91
+ # they will be mapped one by one
92
+ def subfields_from_single_map
93
+ return [] if @single_mapping.empty?
94
+
95
+ mapped_subfields = []
96
+ @single_mapping.each do |from, to|
97
+ subfields = subfields_from_to(@from_datafield, from, to)
98
+ mapped_subfields.concat(subfields)
99
+ end
100
+ mapped_subfields
101
+ end
102
+
103
+ # return all subfields mapped with diferent combined rules - different destination subfield names
104
+ # mapped with all combined rules, exmaple: [[["a,b,c,d", "b", "--"],["o,p,q", "b", ""]],[["x,y,z", "a", "--"]]]
105
+ # mapping using above example rules will return two subfield: $b, $a
106
+ def subfields_from_combined_map
107
+ all_rules = @mapping_rule.combined_rules
108
+ return [] if all_rules.empty?
109
+
110
+ mapped_subfields = []
111
+ all_rules.each do |rules|
112
+ subfield = subfield_on_same_tosubfieldname(rules)
113
+ mapped_subfields.push(subfield) if subfield
114
+ end
115
+ mapped_subfields
116
+ end
117
+
118
+ # create one subfield with a desintaion subfield name
119
+ # input array of rules example: [["a,b,c,d", "b", "--"],["o,p,q", "b", ""]] -- all rules with the same destination subfield name "b"
120
+ # get a subfield$b with a concatenated value
121
+ def subfield_on_same_tosubfieldname(rules)
122
+ return nil if rules.empty?
123
+
124
+ val = subfield_value_on_rules(rules)
125
+ return nil if val.strip.empty?
126
+
127
+ subfield_name_to = rules[0][1]
128
+ Util.subfield(subfield_name_to, Util.remove_extra_symbol(rules, val))
129
+ end
130
+
131
+ # input an array of rules, example: [["a,b,c,d", "b", "--"],["o,p,q", "b", ""]]
132
+ # Theese rules have the same destination subfield name, for example "b" in above example
133
+ # get a value concatenated with values mapped using different rules
134
+ def subfield_value_on_rules(rules)
135
+ val = ''
136
+ rules.each { |rule| val << subfield_value_on_rule(rule) }
137
+ val
138
+ end
139
+
140
+ # input a rule (for example ["a,b,c,d", "b", "--"]),
141
+ # get a combined value of subfield a,b,c,d concatenated by " -- " as above example
142
+ # One subfield names may occurs mutiple times in a an orignal field
143
+ def subfield_value_on_rule(rule)
144
+ subfield_names_from = rule[0].strip.split(',')
145
+ symbol = Util.concatenation_symbol(rule[2])
146
+ val = ''
147
+ subfield_names_from.each do |subfield_name|
148
+ sub_val = combined_subfield_value(@from_datafield, subfield_name, symbol)
149
+ val << sub_val
150
+ end
151
+ val
152
+ end
153
+
154
+ # 880 datafield: reverse tag from 'to_tag' defined mapping rule to '880'
155
+ def reversed_880_field(f)
156
+ update_datafield6(f)
157
+ f.tag = '880'
158
+ f
159
+ end
160
+
161
+ # update subfield6 tag with destination tag from the rule
162
+ # since an origin tag may have been mapped a different tag - destination tag
163
+ def update_datafield6(f) # need test
164
+ f['6'].sub!(@mapping_rule.tag_origin, @mapping_rule.tag_destination)
165
+ end
166
+
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,112 @@
1
+ require 'marc'
2
+
3
+ module BerkeleyLibrary
4
+ module TIND
5
+ module Mapping
6
+ module TindFieldUtil
7
+
8
+ # tag - regular alma field
9
+ # referred tag - got tag from subfield6 value of a 880 field
10
+ # nil rule caused by nil referred tag - eg. 880 subfild6 has a value in wrong format
11
+ def rule(field)
12
+ tag = origin_mapping_tag(field)
13
+ return nil unless tag
14
+
15
+ rules[Util.tag_symbol(tag)]
16
+ end
17
+
18
+ def tindfield_existed?(field, fields)
19
+ return false unless field_has_rule?(field)
20
+
21
+ field_rule = rule(field)
22
+ mapping_to_tag = field_rule.pre_existed_tag
23
+ return false unless mapping_to_tag
24
+
25
+ map_to_tag_existed_in_fields?(field, fields, mapping_to_tag)
26
+ end
27
+
28
+ # To check TIND datafield and the specific subfield from rule existed
29
+ def tindfield_subfield_existed?(field, fields)
30
+ return false unless field_has_rule?(field)
31
+
32
+ field_rule = rule(field)
33
+ return false unless pre_existed_tag_subfield_in_rule?(field_rule)
34
+
35
+ tag_subfield = field_rule.pre_existed_tag_subfield
36
+ mapping_to_tag = tag_subfield[0]
37
+ return false unless map_to_tag_existed_in_fields?(field, fields, mapping_to_tag)
38
+
39
+ existed_datafield = field_pre_existed(mapping_to_tag, field, fields)
40
+ return false unless existed_datafield
41
+
42
+ subfield_name = tag_subfield[1]
43
+ existed_datafield[subfield_name] ? true : false
44
+ end
45
+
46
+ def field_880_on_subfield6_tag(tag, fields)
47
+ datafield_on_tag(tag, fields) { |f| referred_tag(f) == tag }
48
+ end
49
+
50
+ def field_on_tag(tag, fields)
51
+ datafield_on_tag(tag, fields) { |f| f.tag == tag }
52
+ end
53
+
54
+ private
55
+
56
+ def field_has_rule?(field)
57
+ field_rule = rule(field)
58
+ return false unless field_rule
59
+
60
+ true
61
+ end
62
+
63
+ def pre_existed_tag_subfield_in_rule?(rule)
64
+ tag_subfield = rule.pre_existed_tag_subfield
65
+ return false unless tag_subfield
66
+
67
+ return false unless tag_subfield.length == 2
68
+
69
+ true
70
+ end
71
+
72
+ def map_to_tag_existed_in_fields?(field, fields, mapping_to_tag)
73
+ existed_tags = if is_880_field?(field)
74
+ tags_from_fields(fields) { |f| tag_from_880_subfield6(f) }
75
+ else
76
+ tags_from_fields(fields, &:tag)
77
+ end
78
+
79
+ existed_tags.include? mapping_to_tag
80
+ end
81
+
82
+ # field, fields be both regular fields
83
+ # or field, fields be both 880 fields
84
+ # since a field may mapped to another one in TIND, mapping_to_tag is not always the same as field.tag
85
+ def field_pre_existed(mapping_to_tag, field, fields)
86
+ if is_880_field?(field)
87
+ field_880_on_subfield6_tag(mapping_to_tag,
88
+ fields)
89
+ else
90
+ field_on_tag(mapping_to_tag, fields)
91
+ end
92
+ end
93
+
94
+ def datafield_on_tag(tag, fields)
95
+ fields.find do |f|
96
+ yield(f, tag)
97
+ end
98
+ end
99
+
100
+ def tags_from_fields(fields, &block)
101
+ fields.map(&block)
102
+ end
103
+
104
+ def tag_from_880_subfield6(field)
105
+ field['6'].split('-')[0]
106
+ end
107
+
108
+ end
109
+
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,134 @@
1
+ require 'marc'
2
+
3
+ module BerkeleyLibrary
4
+ module TIND
5
+ module Mapping
6
+ class TindMarc
7
+ include CsvMapper
8
+ include Util
9
+ include TindSubfieldUtil
10
+ include Misc
11
+ include TindFieldUtil
12
+ include AdditionalDatafieldProcess
13
+ include BerkeleyLibrary::Logging
14
+ include MatchTindField
15
+
16
+ attr_accessor :source_marc_record
17
+ attr_writer :tind_external_datafields
18
+ attr_reader :field_catalog
19
+ attr_reader :mms_id
20
+
21
+ # input an alma record
22
+ def initialize(record)
23
+ @source_marc_record = record
24
+ @field_catalog = DataFieldsCatalog.new(@source_marc_record)
25
+ @tind_external_datafields = []
26
+ end
27
+
28
+ # return mapped tind datafields
29
+ # keep the order of different mapping
30
+ def tindfields
31
+ fields = []
32
+ fields.concat tindfields_group
33
+ fields.concat tindfields_group_880
34
+ fields
35
+ end
36
+
37
+ # return a TIND Marc record
38
+ # add external datafields
39
+ # flag to do additional TIND datafield process before generating a TIND Marc record
40
+ def tind_record
41
+ fields = tindfields
42
+ fields.concat @tind_external_datafields
43
+ more_process(fields)
44
+ record = ::MARC::Record.new
45
+ fields.each { |f| record.append(f) }
46
+ record
47
+ end
48
+
49
+ private
50
+
51
+ # return mapped tind datafields
52
+ # keep the order of different mapping
53
+ def tindfields_group
54
+ fields_from_normal = tindfields_from_normal(@field_catalog.data_fields_group[:normal])
55
+ fields_from_leader = TindFieldFromLeader.new(@source_marc_record).to_datafields
56
+
57
+ temp_fields = fields_from_normal.concat fields_from_leader
58
+ temp_fields.concat tindfields_from_control(temp_fields)
59
+ temp_fields.concat tindfields_with_pre_existed_field(@field_catalog.data_fields_group[:pre_tag], temp_fields)
60
+ temp_fields.concat tindfields_with_pre_existed_subfield(@field_catalog.data_fields_group[:pre_tag_subfield], temp_fields)
61
+
62
+ temp_fields
63
+ end
64
+
65
+ # return mapped tind 880 datafields
66
+ # keep the order of different mapping
67
+ def tindfields_group_880
68
+ fields = []
69
+ fields.concat tindfields_from_normal(@field_catalog.data_fields_880_group[:normal])
70
+ fields.concat tindfields_with_pre_existed_field(@field_catalog.data_fields_880_group[:pre_tag], fields)
71
+ fields.concat tindfields_with_pre_existed_subfield(@field_catalog.data_fields_880_group[:pre_tag_subfield], fields)
72
+ fields.concat @field_catalog.data_fields_880_00
73
+ fields
74
+ end
75
+
76
+ # # Return TIND datafields mapped in a normal way
77
+ # # Normal way mapping: one regular datafield is mapped one TIND datafield
78
+ def tindfields_from_normal(alma_fields)
79
+ new_fls = []
80
+ alma_fields.each do |f|
81
+ add_tindfield(new_fls, f, excluding_subfield: false)
82
+ end
83
+ new_fls
84
+ end
85
+
86
+ # Return TIND datafield mapped from a control datafield
87
+ # One control datafield could be mapped to multiple TIND datafields
88
+ def tindfields_from_control(currentfields)
89
+ new_fls = []
90
+ @field_catalog.control_fields.each do |f|
91
+ add_tindcontrolfield(new_fls, f, currentfields)
92
+ end
93
+ new_fls
94
+ end
95
+
96
+ # Return TIND datafields if no pre_existed field
97
+ def tindfields_with_pre_existed_field(alma_fields, currentfields)
98
+ new_fls = []
99
+ alma_fields.each do |f|
100
+ add_tindfield(new_fls, f, excluding_subfield: false) unless tindfield_existed?(f, currentfields)
101
+ end
102
+ new_fls
103
+ end
104
+
105
+ # Return TIND datafields considering excluding pre_existing subfields
106
+ def tindfields_with_pre_existed_subfield(alma_fields, currentfields)
107
+ new_fls = []
108
+ alma_fields.each do |f|
109
+ excluding_subfield = tindfield_subfield_existed?(f, currentfields)
110
+ add_tindfield(new_fls, f, excluding_subfield: excluding_subfield)
111
+ end
112
+ new_fls
113
+ end
114
+
115
+ def add_tindfield(fls, f, excluding_subfield: false)
116
+ tindfield = TindFieldFromSingleMap.new(f, excluding_subfield).to_datafield
117
+ fls << tindfield if tindfield
118
+ end
119
+
120
+ def add_tindcontrolfield(fls, f, currentfields)
121
+ fls.concat TindFieldFromMultipleMap.new(f, currentfields).to_datafields
122
+ end
123
+
124
+ # Additional processes - run in a sequence
125
+ def more_process(fields)
126
+ remove_repeats(fields)
127
+ clean_subfields(fields)
128
+ un_matched_fields_880(fields, @field_catalog.mms_id)
129
+ end
130
+
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,154 @@
1
+ require 'marc'
2
+
3
+ module BerkeleyLibrary
4
+ module TIND
5
+ module Mapping
6
+ module TindSubfieldUtil
7
+
8
+ def clean_subfield(subfield)
9
+ new_value = clr_value(subfield.value)
10
+ subfield.value = new_value
11
+ end
12
+
13
+ def fields_880_subfield6(datafields_880)
14
+ formated_subfield6_value_arr(fields_by(datafields_880) { |f| is_880_field?(f) })
15
+ end
16
+
17
+ # From all subfield 6 gotten for repeated fields - with the same tag
18
+ # return the first subfield 6
19
+ def the_first_subfield6(fields)
20
+ values = subfield_6_values(fields)
21
+ return nil if values.empty?
22
+
23
+ # keep it here, in case needed in future: this can make sure
24
+ # 880 and regular fields having matching sequence number
25
+ # subfield6_with_small_no(values)
26
+
27
+ # new implementation: keep the first subfield 6 value
28
+ logger.warn("#{f[0].tag} have multiple datafields with multiple subfield 6, the first subfield 6 is kept") if values.length > 1
29
+ Util.subfield('6', values[0])
30
+ end
31
+
32
+ private
33
+
34
+ def subfield6?(f)
35
+ !f['6'].nil?
36
+ end
37
+
38
+ # f.tag can be a string or integer
39
+ def is_880_field?(f)
40
+ f.tag.to_s == '880'
41
+ end
42
+
43
+ # return subfield6 value formated the same way for both 880 and regular datafields
44
+ def formated_subfield6_value(f)
45
+ is_880_field?(f) ? formated_subfield6_from_880(f) : formated_subfield6_from_regular_field(f)
46
+ end
47
+
48
+ def fields_by(fields, &block)
49
+ fields.select(&block)
50
+ end
51
+
52
+ # return array of formated subfield6 values on inputted datafields
53
+ def formated_subfield6_value_arr(fields_source)
54
+ # fields_source = is_880_field ? fields_880(datafields) : fields_regular(datafields)
55
+ ls = []
56
+ fields_source.map do |f|
57
+ next unless subfield6?(f)
58
+
59
+ ls << formated_subfield6_value(f)
60
+ end
61
+ ls.compact
62
+ end
63
+
64
+ # return formated field6 for a regular datafield
65
+ # tag:246, subfields: 880-02 => 880-246-02
66
+ def formated_subfield6_from_regular_field(f)
67
+ return nil unless f['6']
68
+
69
+ tag = f.tag
70
+ arr = f['6'].strip.split('-')
71
+ "#{arr[0]}-#{tag}-#{arr[1]}"
72
+ end
73
+
74
+ # return formated subfield6 for a 880 datafield
75
+ # tag: 880, subfield6: 245-01/$1 => 880-245-01
76
+ def formated_subfield6_from_880(f)
77
+ return nil unless f['6']
78
+
79
+ "#{f.tag}-#{f['6'].strip[0, 6].strip}"
80
+ end
81
+
82
+ # return subfields of specific code
83
+ # Datafield returned from Alma may have mutiple subfields with the same code
84
+ def subfields(field, code)
85
+ sf = []
86
+ field.each do |s|
87
+ next unless s.code == code
88
+
89
+ captilize_subfield(s) if code == '3'
90
+ sf << s
91
+ end
92
+ sf
93
+ end
94
+
95
+ def captilize_subfield(subfield)
96
+ new_value = subfield.value.capitalize
97
+ subfield.value = new_value
98
+ end
99
+
100
+ # Combine multiple subfield values based on definition from csv file
101
+ def combined_subfield_value(field, code, symbol)
102
+ sf_arr = subfields(field, code)
103
+ return '' if sf_arr.empty?
104
+
105
+ sf_arr.map(&:value).join(symbol) << symbol # symbol exmaple ' -- '
106
+ end
107
+
108
+ # Mutilpe subfields in one field may have the same name
109
+ # Get all subfields on 'from subfield name'
110
+ # Change subfield names with 'to subfield name'
111
+ def subfields_from_to(field, from, to)
112
+ subfield_arr = subfields(field, from)
113
+ subfield_arr.each { |sf| sf.code = to } if !subfield_arr.empty? && (from != to)
114
+ subfield_arr
115
+ end
116
+
117
+ def subfield6_endwith_00?(f)
118
+ return false unless is_880_field?(f)
119
+
120
+ two_digits = f['6'].strip.split('-')[1][0..1]
121
+ two_digits.to_s == '00'
122
+ end
123
+
124
+ def fields_with_subfield6(fields)
125
+ fields.select { |f| subfield6?(f) }
126
+ end
127
+
128
+ # return subfield 6 with the smallest sequence number
129
+ def subfield_6_values(fields)
130
+ fields_with_subfield6(fields).map(&:value)
131
+ end
132
+
133
+ def subfield6_value_with_lowest_seq_no(values)
134
+ seq = 9999
135
+ txt = nil
136
+ values.each do |val|
137
+ num = seq_no(val)
138
+ if (num > 0) && (num < seq)
139
+ seq = num
140
+ txt = val
141
+ end
142
+ end
143
+ txt
144
+ end
145
+
146
+ # return all subfields except subfield6
147
+ def subfields_without_subfield6(field)
148
+ field.subfields.reject { |sf| sf.code == '6' }
149
+ end
150
+
151
+ end
152
+ end
153
+ end
154
+ end