berkeley_library-tind 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/build.yml +15 -3
- data/.gitignore +3 -0
- data/.idea/inspectionProfiles/Project_Default.xml +10 -0
- data/.idea/tind.iml +4 -3
- data/CHANGES.md +6 -0
- data/README.md +121 -2
- data/berkeley_library-tind.gemspec +1 -0
- data/bin/alma-multiple-tind +50 -0
- data/bin/alma-single-tind +48 -0
- data/bin/save_tind_records +80 -0
- data/bin/tind-marc +73 -0
- data/lib/berkeley_library/tind/mapping/additional_datafield_process.rb +128 -0
- data/lib/berkeley_library/tind/mapping/alma.rb +42 -0
- data/lib/berkeley_library/tind/mapping/alma_base.rb +101 -0
- data/lib/berkeley_library/tind/mapping/alma_multiple_tind.rb +31 -0
- data/lib/berkeley_library/tind/mapping/alma_single_tind.rb +28 -0
- data/lib/berkeley_library/tind/mapping/config.rb +44 -0
- data/lib/berkeley_library/tind/mapping/csv_mapper.rb +35 -0
- data/lib/berkeley_library/tind/mapping/csv_multiple_mapper.rb +41 -0
- data/lib/berkeley_library/tind/mapping/data/one_to_multiple_mapping.csv +4 -0
- data/lib/berkeley_library/tind/mapping/data/one_to_one_mapping.csv +39 -0
- data/lib/berkeley_library/tind/mapping/external_tind_field.rb +103 -0
- data/lib/berkeley_library/tind/mapping/field_catalog.rb +146 -0
- data/lib/berkeley_library/tind/mapping/field_catalog_util.rb +59 -0
- data/lib/berkeley_library/tind/mapping/match_tind_field.rb +77 -0
- data/lib/berkeley_library/tind/mapping/misc.rb +69 -0
- data/lib/berkeley_library/tind/mapping/multiple_rule.rb +36 -0
- data/lib/berkeley_library/tind/mapping/single_rule.rb +143 -0
- data/lib/berkeley_library/tind/mapping/tind_control_subfield.rb +59 -0
- data/lib/berkeley_library/tind/mapping/tind_field.rb +49 -0
- data/lib/berkeley_library/tind/mapping/tind_field_from_leader.rb +27 -0
- data/lib/berkeley_library/tind/mapping/tind_field_from_multiple_map.rb +59 -0
- data/lib/berkeley_library/tind/mapping/tind_field_from_single_map.rb +170 -0
- data/lib/berkeley_library/tind/mapping/tind_field_util.rb +112 -0
- data/lib/berkeley_library/tind/mapping/tind_marc.rb +134 -0
- data/lib/berkeley_library/tind/mapping/tind_subfield_util.rb +154 -0
- data/lib/berkeley_library/tind/mapping/util.rb +117 -0
- data/lib/berkeley_library/tind/mapping.rb +1 -0
- data/lib/berkeley_library/tind/module_info.rb +1 -1
- data/lib/berkeley_library/util/files.rb +1 -2
- data/spec/berkeley_library/tind/mapping/additional_datafield_process_spec.rb +35 -0
- data/spec/berkeley_library/tind/mapping/alma_base_spec.rb +115 -0
- data/spec/berkeley_library/tind/mapping/alma_multiple_tind_spec.rb +20 -0
- data/spec/berkeley_library/tind/mapping/alma_single_tind_spec.rb +87 -0
- data/spec/berkeley_library/tind/mapping/alma_spec.rb +28 -0
- data/spec/berkeley_library/tind/mapping/config_spec.rb +19 -0
- data/spec/berkeley_library/tind/mapping/csv_mapper_spec.rb +27 -0
- data/spec/berkeley_library/tind/mapping/csv_multiple_mapper_spec.rb +27 -0
- data/spec/berkeley_library/tind/mapping/external_tind_field_spec.rb +45 -0
- data/spec/berkeley_library/tind/mapping/field_catalog_spec.rb +78 -0
- data/spec/berkeley_library/tind/mapping/field_catalog_util_spec.rb +57 -0
- data/spec/berkeley_library/tind/mapping/match_tind_field_spec.rb +25 -0
- data/spec/berkeley_library/tind/mapping/misc_spec.rb +51 -0
- data/spec/berkeley_library/tind/mapping/multiple_rule_spec.rb +44 -0
- data/spec/berkeley_library/tind/mapping/single_rule_spec.rb +52 -0
- data/spec/berkeley_library/tind/mapping/tind_control_subfield_spec.rb +96 -0
- data/spec/berkeley_library/tind/mapping/tind_field_from_leader_spec.rb +21 -0
- data/spec/berkeley_library/tind/mapping/tind_field_from_multiple_map_spec.rb +31 -0
- data/spec/berkeley_library/tind/mapping/tind_field_from_single_map_spec.rb +150 -0
- data/spec/berkeley_library/tind/mapping/tind_field_spec.rb +60 -0
- data/spec/berkeley_library/tind/mapping/tind_field_util_spec.rb +68 -0
- data/spec/berkeley_library/tind/mapping/tind_marc_spec.rb +88 -0
- data/spec/berkeley_library/tind/mapping/tind_subfield_util_spec.rb +48 -0
- data/spec/berkeley_library/tind/mapping/util_spec.rb +56 -0
- data/spec/berkeley_library/tind/marc/xml_writer_spec.rb +24 -0
- data/spec/data/mapping/991032333019706532-sru.xml +216 -0
- data/spec/data/mapping/one_to_multiple_mapping.csv +4 -0
- data/spec/data/mapping/one_to_one_mapping.csv +39 -0
- data/spec/data/mapping/record.xml +263 -0
- data/spec/data/mapping/record_not_qualified.xml +36 -0
- metadata +105 -2
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'marc'
|
2
|
+
|
3
|
+
module BerkeleyLibrary
|
4
|
+
module TIND
|
5
|
+
module Mapping
|
6
|
+
module MatchTindField
|
7
|
+
|
8
|
+
# return regular fields without matched 880 fields
|
9
|
+
# return 880 fields without matched regular fields
|
10
|
+
def un_matched_fields_880(fields, mms_id)
|
11
|
+
unmached_fields = []
|
12
|
+
|
13
|
+
str_arr_from_880 = subfield6_values_from_880_fields(fields)
|
14
|
+
str_arr_from_regular = subfield6_values_from_regular_fields(fields)
|
15
|
+
|
16
|
+
fields_tobe_validated = fields_need_880_validation(fields)
|
17
|
+
|
18
|
+
fields_880_tobe_validated = fields_tobe_validated.select { |f| is_880_field?(f) }
|
19
|
+
fields_regular_tobe_validated = fields_tobe_validated.reject { |f| is_880_field?(f) }
|
20
|
+
|
21
|
+
unmached_fields.concat un_matched_fields(fields_880_tobe_validated, str_arr_from_regular)
|
22
|
+
unmached_fields.concat un_matched_fields(fields_regular_tobe_validated, str_arr_from_880)
|
23
|
+
|
24
|
+
log_warning(unmached_fields, mms_id)
|
25
|
+
end
|
26
|
+
|
27
|
+
def check_abnormal_formated_subfield6(fields)
|
28
|
+
fields.each { |f| check_subfield6_format(f) if check_subfield6?(f) }
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def subfield6_values_from_880_fields(fields)
|
34
|
+
formated_subfield6_value_arr(fields_by(fields) { |f| is_880_field?(f) })
|
35
|
+
end
|
36
|
+
|
37
|
+
def subfield6_values_from_regular_fields(fields)
|
38
|
+
formated_subfield6_value_arr(fields_by(fields) { |f| !is_880_field?(f) })
|
39
|
+
end
|
40
|
+
|
41
|
+
def fields_need_880_validation(fields)
|
42
|
+
fields_with_subfield6(fields).reject { |f| subfield6_endwith_00?(f) }
|
43
|
+
end
|
44
|
+
|
45
|
+
# return true when field has a matched 880 field,
|
46
|
+
# or an 880 field has a matched regular field
|
47
|
+
def match?(f, arr)
|
48
|
+
str = formated_subfield6_value(f)
|
49
|
+
arr.include? str
|
50
|
+
end
|
51
|
+
|
52
|
+
def un_matched_fields(fields, arr)
|
53
|
+
fds = []
|
54
|
+
fields.each { |f| fds << f unless match?(f, arr) }
|
55
|
+
fds
|
56
|
+
end
|
57
|
+
|
58
|
+
def log_warning(fields, mms_id)
|
59
|
+
warning_message_for_rspec = []
|
60
|
+
fields.each do |f|
|
61
|
+
msg = "Please check 880 matching: mms_id: #{mms_id}, tag: #{f.tag}, value: #{f['6']} "
|
62
|
+
warning_message_for_rspec << msg
|
63
|
+
logger.warn(msg)
|
64
|
+
end
|
65
|
+
warning_message_for_rspec
|
66
|
+
end
|
67
|
+
|
68
|
+
def check_subfield6?(f)
|
69
|
+
return false if ::MARC::ControlField.control_tag?(f.tag)
|
70
|
+
|
71
|
+
f['6'] ? true : false
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'marc'
|
2
|
+
|
3
|
+
module BerkeleyLibrary
|
4
|
+
module TIND
|
5
|
+
module Mapping
|
6
|
+
module Misc
|
7
|
+
|
8
|
+
#### referred tag ###
|
9
|
+
def origin_mapping_tag(f)
|
10
|
+
is_880_field?(f) ? referred_tag(f) : f.tag
|
11
|
+
end
|
12
|
+
|
13
|
+
# get the 880 referred tag.
|
14
|
+
# An example $6 value: '650-05/$1', referred tag is 650
|
15
|
+
def referred_tag(field)
|
16
|
+
return nil unless subfield6?(field)
|
17
|
+
|
18
|
+
field['6'].strip.split('-')[0]
|
19
|
+
end
|
20
|
+
|
21
|
+
# check a tag in subfield 6 of a 880 datafield
|
22
|
+
def field_880_has_referred_tag?(tag, field)
|
23
|
+
referred_tag_from_880 = referred_tag(field)
|
24
|
+
return false unless referred_tag_from_880
|
25
|
+
|
26
|
+
referred_tag_from_880 == tag
|
27
|
+
end
|
28
|
+
|
29
|
+
### referred tag end ###
|
30
|
+
|
31
|
+
# add subfield6 validation
|
32
|
+
def check_subfield6_format(f)
|
33
|
+
val = f['6']
|
34
|
+
reg1 = %r{^\d{3}-\d{2}/}
|
35
|
+
reg2 = /^\d{3}-\d{2}$/
|
36
|
+
|
37
|
+
logger.warn("Unusual subfield6 format: #{val}; correct format examples: 1) 880-02 ; 2)246-02/$1") unless reg1.match(val) || reg2.match(val)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# manipulate original values
|
43
|
+
# Delete characters when occuring at the end of a subfield value
|
44
|
+
def rm_punctuation(str)
|
45
|
+
return str if str.empty? || str.nil?
|
46
|
+
|
47
|
+
punctuations = Config.punctuations
|
48
|
+
char = str[-1]
|
49
|
+
return str unless punctuations.include? char
|
50
|
+
|
51
|
+
rm_punctuation(str.delete_suffix!(char))
|
52
|
+
end
|
53
|
+
|
54
|
+
def clr_value(value)
|
55
|
+
new_value = rm_punctuation(value)
|
56
|
+
['[', ']'].each { |v| value.gsub!(v, ' ') }
|
57
|
+
new_value.strip
|
58
|
+
end
|
59
|
+
|
60
|
+
# input example: 1) 880-02 ; 2)246-02/$1
|
61
|
+
def seq_no(value)
|
62
|
+
# logger if not started with ***-** format
|
63
|
+
value.split('/')[0].split('-')[1].to_i # nil.to_i => 0, ''.to_i = >0
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module BerkeleyLibrary
|
2
|
+
module TIND
|
3
|
+
module Mapping
|
4
|
+
|
5
|
+
class MultipleRule
|
6
|
+
include Util
|
7
|
+
|
8
|
+
attr_reader :tag_origin
|
9
|
+
attr_reader :tag_destination
|
10
|
+
attr_reader :indicator
|
11
|
+
attr_reader :pre_existed_tag
|
12
|
+
attr_reader :subfield_key
|
13
|
+
attr_reader :position_from_to
|
14
|
+
|
15
|
+
def initialize(row)
|
16
|
+
@tag_origin = row[:tag_origin]
|
17
|
+
@tag_destination = row[:tag_destination]
|
18
|
+
@indicator = Util.indicator(row[:new_indecator])
|
19
|
+
@pre_existed_tag = row[:map_if_no_this_tag_existed]
|
20
|
+
@subfield_key = row[:subfield_key]
|
21
|
+
@position_from_to = extract_position(row[:value_from], row[:value_to])
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# return an array with string positons for extracting value
|
27
|
+
def extract_position(f, t)
|
28
|
+
return nil unless f && t
|
29
|
+
|
30
|
+
[f.to_i, t.to_i]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module BerkeleyLibrary
|
2
|
+
module TIND
|
3
|
+
module Mapping
|
4
|
+
# TODO: ADD CSV VALIDATION, WHEN NEED ADD A NEW MAPPING CSV FILE
|
5
|
+
# 1. not empty row
|
6
|
+
# 2. a subfield name can appear in either normal mapping or combine mapping, not both
|
7
|
+
# 3. single map has the same amount of from names and to names
|
8
|
+
# 4. Combine mappping should have tree columns, validate more?
|
9
|
+
# 5. Combine from_subfield, to_subfield should have values, no empty
|
10
|
+
# 6. Tag from row[:map_if_no_this_tag_subfield_existed]), row[:map_if_no_this_tag_existed] # This tag should be the same as destination tag
|
11
|
+
# 7. In single map csv, one row cannot have both "map_if_no_this_tag_existed" (245) and ":map_if_no_this_tag_subfield_existed"
|
12
|
+
# (245__b) because tag in these two column are identical
|
13
|
+
# 8. csv file validation - a row should have coulumns: tag origin and destintation ? single rule
|
14
|
+
# 9. Validating these column names
|
15
|
+
# 10. csv file validation - a row should have coulumns: tag origin and destintation ? single rule
|
16
|
+
# 11. validating headers
|
17
|
+
# 12. Formats for some of the columns
|
18
|
+
|
19
|
+
class SingleRule
|
20
|
+
include Util
|
21
|
+
attr_reader :tag_origin
|
22
|
+
attr_reader :tag_destination
|
23
|
+
attr_reader :indicator
|
24
|
+
attr_reader :pre_existed_tag
|
25
|
+
attr_reader :pre_existed_tag_subfield
|
26
|
+
attr_reader :single_rule_hash
|
27
|
+
attr_reader :single_rule_subfield_excluded_hash
|
28
|
+
attr_reader :combined_rules
|
29
|
+
|
30
|
+
def initialize(row)
|
31
|
+
@tag_origin = row[:tag_origin]
|
32
|
+
@tag_destination = row[:tag_destination]
|
33
|
+
@indicator = Util.indicator(row[:new_indecator])
|
34
|
+
@pre_existed_tag = row[:map_if_no_this_tag_existed]
|
35
|
+
@pre_existed_tag_subfield = existed_tag_subfield(row[:map_if_no_this_tag_subfield_existed]) # This tag should be the same as destination tag
|
36
|
+
@single_rule_hash = single_map_dic(row[:subfield_single_from], row[:subfield_single_to])
|
37
|
+
@single_rule_subfield_excluded_hash = single_map_subfield_excluded_dic
|
38
|
+
@combined_rules = rules_with_same_subfield_name(row)
|
39
|
+
end
|
40
|
+
|
41
|
+
# 1. Return an array of combined rules, an item in the array
|
42
|
+
# is an array of rules which have the same 'to subfield name'
|
43
|
+
# 2. An example: [[["a,b,c,d", "b", "--"],["o,p,q", "b", ""]],[["x,y,z", "a", "--"]]]
|
44
|
+
def rules_with_same_subfield_name(row)
|
45
|
+
rules = all_combined_rules(row)
|
46
|
+
identical_to_subfield_names = unique_tosubfield_names(rules)
|
47
|
+
identical_to_subfield_names.each_with_object([]) do |name, result|
|
48
|
+
result << rules_with_sametosubfield(name, rules)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
# return an array of tag and subfield name, example '255__a' => ['255','a']
|
55
|
+
def existed_tag_subfield(str)
|
56
|
+
str.nil? ? nil : str.split('__')
|
57
|
+
end
|
58
|
+
|
59
|
+
# list identical 'to subfield name's from combined mapping rules
|
60
|
+
# (an example rule ['a,b,c', 'b', ' -- '])
|
61
|
+
def unique_tosubfield_names(rules)
|
62
|
+
names = rules.map { |rule| rule[1] }
|
63
|
+
names.uniq
|
64
|
+
end
|
65
|
+
|
66
|
+
# numbers of combined rules
|
67
|
+
def combined_rule_counts(row)
|
68
|
+
headers = row.headers
|
69
|
+
headers.select { |h| h.to_s.include? 'subfield_combined_from_' }.count
|
70
|
+
end
|
71
|
+
|
72
|
+
# Three coulumns 'subfield_combined_from_*','subfield_combined_to_*','symbol_*'
|
73
|
+
# define a combined mapping rule
|
74
|
+
def combined_rule(row, i)
|
75
|
+
from_subfield = row["subfield_combined_from_#{i}".to_sym]
|
76
|
+
to_subfield = row["subfield_combined_to_#{i}".to_sym]
|
77
|
+
s = row["symbol_#{i}".to_sym]
|
78
|
+
from_subfield.nil? || to_subfield.nil? ? nil : [from_subfield, to_subfield, s] # add validation rule , such as not empty later
|
79
|
+
end
|
80
|
+
|
81
|
+
def all_combined_rules(row)
|
82
|
+
rules = []
|
83
|
+
n = combined_rule_counts(row)
|
84
|
+
(1..n).each do |i|
|
85
|
+
rule = combined_rule(row, i)
|
86
|
+
rules << rule if rule
|
87
|
+
end
|
88
|
+
rules
|
89
|
+
end
|
90
|
+
|
91
|
+
# list all combined rules with the same 'to subfield name'
|
92
|
+
def rules_with_sametosubfield(name, rules)
|
93
|
+
rules.each_with_object([]) do |rule, result|
|
94
|
+
result << rule if rule[1] == name
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Define a hash for single map rules, key is 'from subfield name',
|
99
|
+
# value is 'to subfield name'
|
100
|
+
def single_map_dic(str_from, str_to)
|
101
|
+
dic = {}
|
102
|
+
if should_single_map?(str_from, str_to)
|
103
|
+
arr_from = str_from.strip.split(',')
|
104
|
+
arr_to = str_to.strip.split(',')
|
105
|
+
arr_from.each_with_index { |from_name, i| dic[from_name.to_s] = arr_to[i].to_s }
|
106
|
+
end
|
107
|
+
dic
|
108
|
+
end
|
109
|
+
|
110
|
+
# Hash removed the excluding subfield
|
111
|
+
def single_map_subfield_excluded_dic
|
112
|
+
dic = @single_rule_hash
|
113
|
+
return dic unless excluding_subfield?
|
114
|
+
|
115
|
+
excluding_subfield_name = @pre_existed_tag_subfield[1].to_s
|
116
|
+
dic.delete(excluding_subfield_name) if dic.key? excluding_subfield_name
|
117
|
+
dic
|
118
|
+
end
|
119
|
+
|
120
|
+
# Check excluding subfield
|
121
|
+
def excluding_subfield?
|
122
|
+
return false unless @pre_existed_tag_subfield
|
123
|
+
return false unless @pre_existed_tag_subfield[1]
|
124
|
+
|
125
|
+
true
|
126
|
+
end
|
127
|
+
|
128
|
+
# add this to validation
|
129
|
+
def should_single_map?(str_from, str_to)
|
130
|
+
return false unless str_from && str_to
|
131
|
+
|
132
|
+
arr_from = str_from.split(',')
|
133
|
+
arr_to = str_to.split(',')
|
134
|
+
return false unless arr_from.count == arr_to.count
|
135
|
+
|
136
|
+
true
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'marc'
|
2
|
+
|
3
|
+
module BerkeleyLibrary
|
4
|
+
module TIND
|
5
|
+
module Mapping
|
6
|
+
module TindControlSubfield
|
7
|
+
|
8
|
+
def extract_value(rule, value)
|
9
|
+
pos = rule.position_from_to
|
10
|
+
return nil unless pos
|
11
|
+
|
12
|
+
value[pos[0]..pos[1]]
|
13
|
+
end
|
14
|
+
|
15
|
+
# return a mapped datafield based on rule and extract value
|
16
|
+
def extracted_field(rule, sub_value)
|
17
|
+
subname = rule.subfield_key
|
18
|
+
destiantion_tag = rule.tag_destination
|
19
|
+
indicator = rule.indicator
|
20
|
+
return nil unless subname && destiantion_tag && indicator
|
21
|
+
|
22
|
+
new_sub_value = clean_subfield_value(destiantion_tag, sub_value)
|
23
|
+
return nil unless new_sub_value
|
24
|
+
|
25
|
+
new_sub_value = clean_subfield_value(destiantion_tag, sub_value)
|
26
|
+
subfields = [Util.subfield(subname, new_sub_value)]
|
27
|
+
Util.datafield(destiantion_tag, indicator, subfields)
|
28
|
+
end
|
29
|
+
|
30
|
+
# pass in rules, a string value; return datafields based on rules
|
31
|
+
def extracted_fields_from_leader(leader_rules, leader_value)
|
32
|
+
new_fls = []
|
33
|
+
leader_rules.each do |rule|
|
34
|
+
sub_value = extract_value(rule, leader_value)
|
35
|
+
next unless sub_value
|
36
|
+
|
37
|
+
newfield = extracted_field(rule, sub_value)
|
38
|
+
new_fls << newfield if newfield
|
39
|
+
end
|
40
|
+
new_fls
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def clean_subfield_value(tag, val)
|
46
|
+
return val if tag != '269'
|
47
|
+
|
48
|
+
new_val = val.downcase.sub(/u$/, '0')
|
49
|
+
qualified_269?(new_val) ? new_val : nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def qualified_269?(val)
|
53
|
+
val =~ /^\d{4}$/
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'marc'
|
2
|
+
|
3
|
+
module BerkeleyLibrary
|
4
|
+
module TIND
|
5
|
+
module Mapping
|
6
|
+
module TindField
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def f_035_from_alma_id(alma_id, value_980)
|
10
|
+
val = "(#{value_980})#{alma_id}"
|
11
|
+
f('035', 'a', val)
|
12
|
+
end
|
13
|
+
|
14
|
+
def f_035(val)
|
15
|
+
f('035', 'a', val)
|
16
|
+
end
|
17
|
+
|
18
|
+
def f_245_p(val)
|
19
|
+
f('245', 'p', val)
|
20
|
+
end
|
21
|
+
|
22
|
+
def f_fft(url, txt = None)
|
23
|
+
return f('FFT', 'a', url) unless txt
|
24
|
+
|
25
|
+
::MARC::DataField.new('FFT', ' ', ' ', ['d', txt], ['a', url])
|
26
|
+
end
|
27
|
+
|
28
|
+
def f_902_d
|
29
|
+
f('902', 'd', Time.now.strftime('%F'))
|
30
|
+
end
|
31
|
+
|
32
|
+
def f_902_n(name_initial)
|
33
|
+
f('902', 'n', name_initial)
|
34
|
+
end
|
35
|
+
|
36
|
+
def f_982_p(val)
|
37
|
+
f('982', 'p', val)
|
38
|
+
end
|
39
|
+
|
40
|
+
def f(tag, code, value)
|
41
|
+
::MARC::DataField.new(tag, ' ', ' ', [code, value])
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'marc'
|
2
|
+
require 'berkeley_library/tind/mapping/tind_control_subfield'
|
3
|
+
|
4
|
+
module BerkeleyLibrary
|
5
|
+
module TIND
|
6
|
+
require 'marc'
|
7
|
+
module Mapping
|
8
|
+
|
9
|
+
class TindFieldFromLeader
|
10
|
+
include CsvMultipleMapper
|
11
|
+
include Util
|
12
|
+
include TindControlSubfield
|
13
|
+
|
14
|
+
def initialize(record)
|
15
|
+
@leader_value = record.leader
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_datafields
|
19
|
+
leader_rules = rules[Util.tag_symbol('LDR')]
|
20
|
+
return [] unless @leader_value && leader_rules
|
21
|
+
|
22
|
+
extracted_fields_from_leader(leader_rules, @leader_value)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -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
|