libis-metadata 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +6 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +39 -0
  8. data/Rakefile +6 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +8 -0
  11. data/exe/metadata +5 -0
  12. data/lib/libis/metadata/cli/cli_downloader.rb +182 -0
  13. data/lib/libis/metadata/cli/cli_helper.rb +74 -0
  14. data/lib/libis/metadata/command_line.rb +25 -0
  15. data/lib/libis/metadata/downloader.rb +117 -0
  16. data/lib/libis/metadata/dublin_core_record.rb +115 -0
  17. data/lib/libis/metadata/field_format.rb +119 -0
  18. data/lib/libis/metadata/fix_field.rb +33 -0
  19. data/lib/libis/metadata/mapper.rb +80 -0
  20. data/lib/libis/metadata/mappers/flandrica.rb +76 -0
  21. data/lib/libis/metadata/mappers/kuleuven.rb +1929 -0
  22. data/lib/libis/metadata/mappers/scope.rb +46 -0
  23. data/lib/libis/metadata/marc21_record.rb +49 -0
  24. data/lib/libis/metadata/marc_record.rb +285 -0
  25. data/lib/libis/metadata/parser/basic_parser.rb +116 -0
  26. data/lib/libis/metadata/parser/dublin_core_parser.rb +35 -0
  27. data/lib/libis/metadata/parser/marc21_parser.rb +205 -0
  28. data/lib/libis/metadata/parser/marc_format_parser.rb +51 -0
  29. data/lib/libis/metadata/parser/marc_rules.rb +34 -0
  30. data/lib/libis/metadata/parser/marc_select_parser.rb +24 -0
  31. data/lib/libis/metadata/parser/patch.rb +22 -0
  32. data/lib/libis/metadata/parser/subfield_criteria_parser.rb +70 -0
  33. data/lib/libis/metadata/parsers.rb +12 -0
  34. data/lib/libis/metadata/sharepoint_mapping.rb +119 -0
  35. data/lib/libis/metadata/sharepoint_record.rb +262 -0
  36. data/lib/libis/metadata/var_field.rb +242 -0
  37. data/lib/libis/metadata/version.rb +5 -0
  38. data/lib/libis/metadata.rb +25 -0
  39. data/lib/libis-metadata.rb +1 -0
  40. data/metadata.gemspec +39 -0
  41. metadata +266 -0
@@ -0,0 +1,35 @@
1
+ require 'parslet'
2
+
3
+ require_relative 'basic_parser'
4
+
5
+ module Libis
6
+ module Metadata
7
+ module Parser
8
+ # noinspection RubyResolve
9
+
10
+ # New style parsers and converters for metadata. New, not finished and untested.
11
+ class DublinCoreParser < Libis::Metadata::Parser::BasicParser
12
+ rule(:namespace) {match('[^:]').repeat(1).as(:namespace) >> str(':')}
13
+ rule(:namespace?) {namespace.maybe}
14
+
15
+ rule(:attribute) {namespace? >> name_string.as(:name) >> str('=') >> str('"') >> match('[^"]').repeat(1).as(:value) >> str('"')}
16
+ rule(:attributes) {attribute >> (spaces >> attribute).repeat}
17
+ rule(:attributes?) {attributes.maybe}
18
+ rule(:element) {name_string.as(:element)}
19
+ rule(:DC) {namespace >> element >> (spaces >> attributes.as(:attributes)).maybe}
20
+
21
+ root(:DC)
22
+
23
+ def to_target(tree)
24
+ tree = tree[:DC]
25
+ return nil unless tree
26
+ result = "xml['#{tree[:namespace]}'].#{tree[:element]}("
27
+ tree[:attributes].each {|attribute| result += "'#{attribute[:name]}' => '#{attribute[:value]}'"}
28
+ result + ').text'
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,205 @@
1
+ require 'parslet'
2
+
3
+ require_relative 'basic_parser'
4
+ require_relative 'marc_rules'
5
+
6
+ module Libis
7
+ module Metadata
8
+ module Parser
9
+ # noinspection RubyResolve
10
+
11
+ # New style parsers and converters for metadata. New, not finished and untested.
12
+ class Marc21Parser < Libis::Metadata::Parser::BasicParser
13
+
14
+ root(:marc21)
15
+ rule(:marc21) {select.as(:select) | format.as(:format)}
16
+
17
+ # select syntax
18
+ rule(:select) do
19
+ str('MARC') >>
20
+ spaces? >> tag.as(:tag) >>
21
+ spaces? >> indicator.maybe.as(:ind1) >> indicator.maybe.as(:ind2) >>
22
+ spaces? >> subfield.maybe.as(:subfield) >>
23
+ spaces? >> condition.maybe.as(:condition)
24
+ end
25
+ rule(:condition) {grouped_anonymous(cond_format.as(:cond_format))}
26
+ rule(:cond_format) {cond_entry.repeat(1).maybe.as(:entry) >> postfix.maybe.as(:postfix)}
27
+ rule(:cond_entry) {sf_reference | method_call | cond_group}
28
+ rule(:cond_group) {(prefix.maybe.as(:prefix) >> grouped(cond_format)).as(:cond_group)}
29
+
30
+ # Formatting syntax
31
+ rule(:format) {entry.repeat(1).maybe.as(:entry) >> postfix.maybe.as(:postfix)}
32
+
33
+ rule(:entry) {sf_reference | method_call | group}
34
+ # noinspection RubyArgCount
35
+ rule(:group) {(prefix.maybe.as(:prefix) >> grouped(format)).as(:group)}
36
+ # noinspection RubyArgCount
37
+ rule(:method_call) {(prefix.maybe.as(:prefix) >> sf_indicator >> grouped_anonymous(format, lrparen)).as(:method_call)}
38
+
39
+ # pre- and postfix
40
+ rule(:prefix) {other.repeat(1)}
41
+ rule(:prefix) {text}
42
+ rule(:postfix) {other.repeat(1)}
43
+ rule(:postfix) {text}
44
+
45
+ # subfield reference
46
+ rule(:sf_reference) {sf_variable.as(:subfield) | sf_fixed.as(:fixfield)}
47
+
48
+ rule(:sf_variable) {prefix.maybe.as(:prefix) >> sf_indicator >> sf_repeat.maybe.as(:repeat) >> sf_name}
49
+ rule(:sf_repeat) {star >> any_quoted(:separator).maybe}
50
+
51
+ rule(:sf_fixed) {prefix.maybe.as(:prefix) >> sf_indicator >> lsparen >> (sf_range | sf_position | sf_star) >> rsparen}
52
+ rule(:sf_star) {star.as(:all)}
53
+ rule(:sf_position) {integer.as(:position)}
54
+ rule(:sf_range) {integer.as(:first) >> minus >> integer.as(:last)}
55
+
56
+ rule(:other) {paren.absent? >> dollar.absent? >> any | litteral_dollar}
57
+
58
+ # tag
59
+ rule(:tag) {tag_numeric | tag_alpha}
60
+ rule(:tag_numeric) {number.repeat(3, 3)}
61
+ rule(:tag_alpha) {character.repeat(3, 3)}
62
+
63
+ # indicator
64
+ rule(:indicator) {hashtag | underscore | number | character}
65
+
66
+ # subfield
67
+ rule(:sf_indicator) {dollar}
68
+ rule(:sf_name) {(character | number).as(:name)}
69
+ rule(:sf_names) {(character | number).repeat(1).as(:names)}
70
+ rule(:subfield) {sf_indicator >> sf_name}
71
+ rule(:litteral_dollar) {dollar >> dollar}
72
+
73
+ # noinspection RubyResolve
74
+ class Transformer < Parslet::Transform
75
+ rule(name: simple(:name)) {"#{name}"}
76
+ # select transformation rules
77
+ rule(cond_group: {
78
+ prefix: simple(:prefix),
79
+ lparen: simple(:lparen),
80
+ entry: simple(:entry),
81
+ postfix: simple(:postfix),
82
+ rparen: simple(:rparen)}) {
83
+ "#{prefix}#{lparen}#{entry}#{postfix}#{rparen}"
84
+ }
85
+ rule(cond_group: {
86
+ prefix: simple(:prefix),
87
+ lparen: simple(:lparen),
88
+ entry: sequence(:entry),
89
+ postfix: simple(:postfix),
90
+ rparen: simple(:rparen)}) {
91
+ "#{prefix}#{lparen}#{entry.join}#{postfix}#{rparen}"
92
+ }
93
+ rule(cond_format: {
94
+ entry: sequence(:entry),
95
+ postfix: simple(:postfix)
96
+ }) {", Proc.new { |f| #{entry.join}#{postfix} }"}
97
+ rule(select: {
98
+ tag: simple(:tag),
99
+ ind1: simple(:ind1),
100
+ ind2: simple(:ind2),
101
+ subfield: simple(:subfield),
102
+ condition: simple(:condition)
103
+ }) {"record.select_fields('#{tag}#{ind1 || '#'}#{ind2 || '#'}#{subfield}'#{condition || ''})"}
104
+ # format transformation rules
105
+ rule(format: {
106
+ entry: sequence(:entries),
107
+ postfix: simple(:postfix)
108
+ }) do
109
+ if entries.size == 1 && postfix.nil?
110
+ entries.first
111
+ else
112
+ "field_format(#{entries.join(',')}#{", postfix: '#{postfix}'" if postfix}).to_s"
113
+ end
114
+ end
115
+ rule(group: {
116
+ prefix: simple(:prefix),
117
+ lparen: simple(:lparen),
118
+ entry: nil,
119
+ postfix: simple(:postfix),
120
+ rparen: simple(:rparen)}) {
121
+ "#{prefix}#{lparen}#{postfix}#{rparen}"
122
+ }
123
+ rule(group: {
124
+ prefix: simple(:prefix),
125
+ lparen: simple(:lparen),
126
+ entry: '',
127
+ postfix: simple(:postfix),
128
+ rparen: simple(:rparen)}) {
129
+ "#{prefix}#{lparen}#{postfix}#{rparen}"
130
+ }
131
+ rule(group: {
132
+ prefix: simple(:prefix),
133
+ lparen: simple(:lparen),
134
+ entry: simple(:entry),
135
+ postfix: simple(:postfix),
136
+ rparen: simple(:rparen)}) {
137
+ "field_format(#{entry}#{", prefix: '#{prefix}#{lparen}'" if prefix || lparen}#{", postfix: '#{postfix}#{rparen}'" if postfix || rparen}).to_s"
138
+ }
139
+ rule(group: {
140
+ prefix: simple(:prefix),
141
+ lparen: simple(:lparen),
142
+ entry: sequence(:entries),
143
+ postfix: simple(:postfix),
144
+ rparen: simple(:rparen)}) {
145
+ "field_format(#{entries.join(',')}#{", prefix: '#{prefix}#{lparen}'" if prefix || lparen}#{", postfix: '#{postfix}#{rparen}'" if postfix || rparen}).to_s"
146
+ }
147
+ rule(fixfield: {
148
+ prefix: nil,
149
+ all: '*'
150
+ }) {'f[]'}
151
+ rule(fixfield: {
152
+ prefix: simple(:prefix),
153
+ all: '*'
154
+ }) {"field_format(f[], prefix: '#{prefix}').to_s"}
155
+ rule(fixfield: {
156
+ prefix: nil,
157
+ position: simple(:position)
158
+ }) {"f[#{position}]"}
159
+ rule(fixfield: {
160
+ prefix: simple(:prefix),
161
+ position: simple(:position)
162
+ }) do
163
+ if prefix
164
+ "field_format(f[#{position}], prefix: '#{prefix}').to_s"
165
+ else
166
+ "f[#{position}]"
167
+ end
168
+ end
169
+ rule(fixfield: {
170
+ prefix: nil,
171
+ first: simple(:from),
172
+ last: simple(:to)
173
+ }) {"f[#{from},#{to}]"}
174
+ rule(fixfield: {
175
+ prefix: simple(:prefix),
176
+ first: simple(:from),
177
+ last: simple(:to)
178
+ }) {"field_format(f[#{from},#{to}], prefix: '#{prefix}').to_s"}
179
+ rule(subfield: {
180
+ prefix: simple(:prefix),
181
+ repeat: nil,
182
+ name: simple(:name),
183
+ }) {"field_format(f.subfield('#{name}'), prefix: '#{prefix}').to_s"}
184
+ rule(subfield: {
185
+ prefix: simple(:prefix),
186
+ repeat: {separator: simple(:separator)},
187
+ name: simple(:name),
188
+ }) {"field_format(f.subfield_array('#{name}')#{", prefix: '#{prefix}'" if prefix}, join: '#{separator}').to_s"}
189
+ rule(subfield: {
190
+ prefix: simple(:prefix),
191
+ repeat: '*',
192
+ name: simple(:name),
193
+ }) {"field_format(f.subfield_array('#{name}')#{", prefix: '#{prefix}'" if prefix}, join: ';').to_s"}
194
+ rule(subfield: {
195
+ prefix: nil,
196
+ repeat: nil,
197
+ name: simple(:name),
198
+ }) {"f.subfield('#{name}')"}
199
+ end
200
+
201
+ end
202
+
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,51 @@
1
+ require 'parslet'
2
+
3
+ require_relative 'basic_parser'
4
+ require_relative 'marc_rules'
5
+
6
+ module Libis
7
+ module Metadata
8
+ module Parser
9
+ # noinspection RubyResolve
10
+
11
+ # New style parsers and converters for metadata. New, not finished and untested.
12
+ class MarcFormatParser < Libis::Metadata::Parser::BasicParser
13
+ include Libis::Metadata::Parser::MarcRules
14
+
15
+ root(:mapping)
16
+
17
+ rule(:mapping) {entry.repeat(1).as(:entry) >> postfix?.as(:postfix)}
18
+
19
+ rule(:entry) {group.as(:group) | sf_reference}
20
+ rule(:group) {prefix?.as(:prefix) >> grouped(mapping)}
21
+
22
+ # pre- and postfix
23
+ rule(:prefix) {other.repeat(1)}
24
+ rule(:prefix) {text}
25
+ rule(:prefix?) {prefix.maybe}
26
+ rule(:postfix) {other.repeat(1)}
27
+ rule(:postfix) {text}
28
+ rule(:postfix?) {postfix.maybe}
29
+
30
+ # subfield reference
31
+ rule(:sf_reference) {sf_variable.as(:subfield) | sf_fixed.as(:fixfield)}
32
+
33
+ rule(:sf_variable) {prefix?.as(:prefix) >> sf_indicator >> sf_repeat?.as(:repeat) >> sf_name}
34
+ rule(:sf_repeat) {star >>
35
+ (dquote >> not_dquote.repeat.as(:separator) >> dquote |
36
+ squote >> not_squote.repeat.as(:separator) >> squote
37
+ ).maybe
38
+ }
39
+ rule(:sf_repeat?) {sf_repeat.maybe}
40
+
41
+ rule(:sf_fixed) {prefix?.as(:prefix) >> sf_indicator >> str('@') >> (sf_position | sf_range | sf_star)}
42
+ rule(:sf_position) {lsparen >> integer.as(:position) >> rsparen}
43
+ rule(:sf_range) {lsparen >> integer.as(:first) >> minus >> integer.as(:last) >> rsparen}
44
+ rule(:sf_star) {star.as(:all)}
45
+
46
+ rule(:other) {paren.absent? >> dollar.absent? >> any | str('$$')}
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,34 @@
1
+ require 'parslet'
2
+
3
+ module Libis
4
+ module Metadata
5
+ module Parser
6
+ # noinspection RubyResolve
7
+
8
+ # New style parsers and converters for metadata. New, not finished and untested.
9
+ module MarcRules
10
+ include Parslet
11
+
12
+ # tag
13
+ rule(:tag) {tag_numeric | tag_alpha}
14
+ rule(:tag_numeric) {number.repeat(3, 3)}
15
+ rule(:tag_alpha) {character.repeat(3, 3)}
16
+
17
+ # indicator
18
+ rule(:indicator) {hashtag | underscore | number | character}
19
+ rule(:indicator?) {indicator.maybe}
20
+ rule(:indicators) {indicator?.as(:ind1) >> indicator?.as(:ind2)}
21
+
22
+ # subfield
23
+ rule(:sf_indicator) {dollar}
24
+ rule(:sf_name) {(character | number).as(:name)}
25
+ rule(:sf_name?) {sf_name.maybe}
26
+ rule(:sf_names) {(character | number).repeat(1).as(:names)}
27
+ rule(:sf_names?) {sf_names.maybe}
28
+ rule(:subfield) {sf_indicator >> sf_name}
29
+
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,24 @@
1
+ require 'parslet'
2
+
3
+ require_relative 'basic_parser'
4
+ require_relative 'marc_rules'
5
+
6
+ module Libis
7
+ module Metadata
8
+ module Parser
9
+ # noinspection RubyResolve
10
+
11
+ # New style parsers and converters for metadata. New, not finished and untested.
12
+ class MarcSelectParser < Libis::Metadata::Parser::BasicParser
13
+ include Libis::Metadata::MarcRules
14
+ root(:MARC)
15
+ rule(:MARC) {str('MARC') >> spaces? >> tag.as(:tag) >> spaces? >> indicators >> spaces? >> subfield.maybe.as(:subfield)}
16
+
17
+ # subfield
18
+ # rule(:sf_condition) { sf_indicator >> sf_names >> (space >> sf_names).repeat }
19
+ # rule(:sf_names) { sf_name.repeat(1) }
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ # New style parsers and converters for metadata. New, not finished and untested.
2
+ class Parslet::Pattern
3
+
4
+ def element_match_hash(tree, exp, bindings)
5
+ return false if exp.size < tree.size
6
+ exp.each do |expected_key, expected_value|
7
+ if expected_key.to_s =~ /^(.*)\?$/
8
+ expected_key = expected_key.is_a?(Symbol) ? $1.to_sym : $1
9
+ return true unless tree.has_key? expected_key
10
+ end
11
+
12
+ return false unless tree.has_key? expected_key
13
+
14
+ # Recurse into the value and stop early on failure
15
+ value = tree[expected_key]
16
+ return false unless element_match(value, expected_value, bindings)
17
+ end
18
+
19
+ true
20
+ end
21
+
22
+ end
@@ -0,0 +1,70 @@
1
+ require 'parslet'
2
+
3
+ require_relative 'basic_parser'
4
+
5
+ module Libis
6
+ module Metadata
7
+ module Parser
8
+ # noinspection RubyResolve
9
+
10
+ # New style parsers and converters for metadata. New, not finished and untested.
11
+ class SubfieldCriteriaParser < Libis::Metadata::Parser::BasicParser
12
+
13
+ root(:criteria)
14
+
15
+ rule(:criteria) {selection >> (spaces >> selection).repeat}
16
+
17
+ rule(:selection) {must >> must_not.maybe}
18
+
19
+ rule(:must) {names.as(:must).maybe >> (one_of | only_one_of).maybe}
20
+ rule(:must_not) {minus >> must.as(:not)}
21
+
22
+ rule(:one_of) {lrparen >> names.as(:one_of) >> rrparen}
23
+ rule(:only_one_of) {lcparen >> names.as(:only_one_of) >> rcparen}
24
+
25
+ rule(:names) {(character | number).repeat(1)}
26
+
27
+ def criteria_to_s(criteria)
28
+ case criteria
29
+ when Array
30
+ # leave as is
31
+ when Hash
32
+ criteria = [criteria]
33
+ else
34
+ return criteria
35
+ end
36
+ criteria.map {|selection| selection_to_s(selection)}.join(' ')
37
+ end
38
+
39
+ def selection_to_s(selection)
40
+ return selection unless selection.is_a? Hash
41
+ result = "#{selection[:must]}"
42
+ result += "(#{selection[:one_of]})" if selection[:one_of]
43
+ result += "{#{selection[:only_one_of]}}" if selection[:only_one_of]
44
+ result += "-#{selection_to_s(selection[:not])}" if selection[:not]
45
+ result
46
+ end
47
+
48
+ def match_criteria(criteria, data)
49
+ tree = self.new.parse(criteria)
50
+ return true if tree.is_a? String
51
+ tree = [tree] unless tree.is_a? Array
52
+ tree.map {|selection| match_selection(selection, data)}.any?
53
+ end
54
+
55
+ def match_selection(selection, data)
56
+ must_match = selection[:must].to_s.split('')
57
+ return false unless must_match == (must_match & data)
58
+ one_of = selection[:one_of].to_s.split('')
59
+ return false unless one_of.empty? || (one_of & data).any?
60
+ only_one_of = selection[:only_one_of].to_s.split('')
61
+ return false unless only_one_of.empty? || (only_one_of & data).size != 1
62
+ return false if match_selection(selection[:not], data) if selection[:not]
63
+ true
64
+ end
65
+
66
+ end
67
+
68
+ end
69
+ end
70
+ end