libis-metadata 0.2.0 → 1.0.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.
@@ -1,46 +1,44 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'libis/tools/metadata/dublin_core_record'
3
+ require 'libis/metadata/dublin_core_record'
4
4
  require 'libis/tools/assert'
5
5
 
6
6
  module Libis
7
- module Tools
8
- module Metadata
9
- module Mappers
10
- # noinspection RubyResolve
7
+ module Metadata
8
+ module Mappers
9
+ # noinspection RubyResolve
11
10
 
12
- # Mixin for {::Libis::Tools::Metadata::DublinCoreRecord} to enable conversion of the Scope exported DC record.
13
- module Scope
11
+ # Mixin for {::Libis::Metadata::DublinCoreRecord} to enable conversion of the Scope exported DC record.
12
+ module Scope
14
13
 
15
- # Main conversion method.
16
- # @return [::Libis::Tools::Metadata::DublinCoreRecord]
17
- def to_dc
18
- assert(self.is_a? Libis::Tools::Metadata::DublinCoreRecord)
14
+ # Main conversion method.
15
+ # @return [::Libis::Metadata::DublinCoreRecord]
16
+ def to_dc
17
+ assert(self.is_a? Libis::Metadata::DublinCoreRecord)
19
18
 
20
- doc = Libis::Tools::Metadata::DublinCoreRecord.new(self.to_xml)
19
+ doc = Libis::Metadata::DublinCoreRecord.new(self.to_xml)
21
20
 
22
- if doc.isPartOf
21
+ if doc.isPartOf
23
22
 
24
- # create new node for isReferencedBy
25
- new_node = doc.add_node(
26
- 'isReferencedBy',
27
- doc.isPartOf.content,
28
- nil,
29
- 'xsi:type' => 'dcterms:URI'
30
- )
23
+ # create new node for isReferencedBy
24
+ new_node = doc.add_node(
25
+ 'isReferencedBy',
26
+ doc.isPartOf.content,
27
+ nil,
28
+ 'xsi:type' => 'dcterms:URI'
29
+ )
31
30
 
32
- # Replace isPartOf with isReferencedBy
33
- doc.isPartOf.replace new_node
34
-
35
- end
36
-
37
- doc
31
+ # Replace isPartOf with isReferencedBy
32
+ doc.isPartOf.replace new_node
38
33
 
39
34
  end
40
35
 
36
+ doc
37
+
41
38
  end
42
39
 
43
40
  end
41
+
44
42
  end
45
43
  end
46
- end
44
+ end
@@ -5,238 +5,236 @@ require 'libis/tools/assert'
5
5
  require_relative 'parser/subfield_criteria_parser'
6
6
 
7
7
  module Libis
8
- module Tools
9
- module Metadata
10
-
11
- # Helper class implementing a variable field for MARC
12
- class VarField
13
-
14
- attr_reader :tag
15
- attr_reader :ind1
16
- attr_reader :ind2
17
- attr_reader :subfield_data
18
-
19
- # Create new variable field with given tag and indicators
20
- # @param [String] tag tag
21
- # @param [String] ind1 first indicator. nil will be translated into empty string.
22
- # @param [String] ind2 second indicator. nil will be translated into empty string.
23
- def initialize(tag, ind1, ind2)
24
- @tag = tag
25
- @ind1 = ind1 || ''
26
- @ind2 = ind2 || ''
27
- @subfield_data = Hash.new { |h, k| h[k] = Array.new }
28
- end
8
+ module Metadata
9
+
10
+ # Helper class implementing a variable field for MARC
11
+ class VarField
12
+
13
+ attr_reader :tag
14
+ attr_reader :ind1
15
+ attr_reader :ind2
16
+ attr_reader :subfield_data
17
+
18
+ # Create new variable field with given tag and indicators
19
+ # @param [String] tag tag
20
+ # @param [String] ind1 first indicator. nil will be translated into empty string.
21
+ # @param [String] ind2 second indicator. nil will be translated into empty string.
22
+ def initialize(tag, ind1, ind2)
23
+ @tag = tag
24
+ @ind1 = ind1 || ''
25
+ @ind2 = ind2 || ''
26
+ @subfield_data = Hash.new {|h, k| h[k] = Array.new}
27
+ end
29
28
 
30
- # Add subfield to variable field
31
- # @param [String] name subfield indicator without '$'
32
- # @param [String] value content of the subfield
33
- def add_subfield(name, value)
34
- @subfield_data[name] << value
35
- end
29
+ # Add subfield to variable field
30
+ # @param [String] name subfield indicator without '$'
31
+ # @param [String] value content of the subfield
32
+ def add_subfield(name, value)
33
+ @subfield_data[name] << value
34
+ end
36
35
 
37
- # dump the contents
38
- #
39
- # @return [String] debug output to inspect the contents of the VarField
40
- def dump
41
- output = "#{@tag}:#{@ind1}:#{@ind2}:\n"
42
- @subfield_data.each { |s, t| output += "\t#{s}:#{t}\n" }
43
- output
44
- end
36
+ # dump the contents
37
+ #
38
+ # @return [String] debug output to inspect the contents of the VarField
39
+ def dump
40
+ output = "#{@tag}:#{@ind1}:#{@ind2}:\n"
41
+ @subfield_data.each {|s, t| output += "\t#{s}:#{t}\n"}
42
+ output
43
+ end
45
44
 
46
- # dump the contents
47
- #
48
- # @return [String] debug output to inspect the contents of the VarField - Single line version
49
- def dump_line
50
- output = "#{@tag}:#{@ind1}:#{@ind2}:"
51
- @subfield_data.each { |s, t| output += "$#{s}#{t}" }
52
- output
53
- end
45
+ # dump the contents
46
+ #
47
+ # @return [String] debug output to inspect the contents of the VarField - Single line version
48
+ def dump_line
49
+ output = "#{@tag}:#{@ind1}:#{@ind2}:"
50
+ @subfield_data.each {|s, t| output += "$#{s}#{t}"}
51
+ output
52
+ end
54
53
 
55
- # list the subfield codes
56
- #
57
- # @return [Array] a list of all subfield codes
58
- def keys
59
- @subfield_data.keys
60
- end
54
+ # list the subfield codes
55
+ #
56
+ # @return [Array] a list of all subfield codes
57
+ def keys
58
+ @subfield_data.keys
59
+ end
61
60
 
62
- # get the first (or only) subfield value for the given code
63
- #
64
- # @return [String] the first or only entry of a subfield or nil if not present
65
- # @param s [Character] the subfield code
66
- def subfield(s)
67
- subfield_array(s).first
68
- end
61
+ # get the first (or only) subfield value for the given code
62
+ #
63
+ # @return [String] the first or only entry of a subfield or nil if not present
64
+ # @param s [Character] the subfield code
65
+ def subfield(s)
66
+ subfield_array(s).first
67
+ end
69
68
 
70
- # get a list of all subfield values for a given code
71
- #
72
- # @return [Array] all the entries of a repeatable subfield
73
- # @param s [Character] the subfield code
74
- def subfield_array(s)
75
- assert(s.is_a?(String) && (s =~ /^[\da-z]$/) == 0, 'method expects a lower case alphanumerical char')
76
- @subfield_data.has_key?(s) ? @subfield_data[s].dup : []
77
- end
69
+ # get a list of all subfield values for a given code
70
+ #
71
+ # @return [Array] all the entries of a repeatable subfield
72
+ # @param s [Character] the subfield code
73
+ def subfield_array(s)
74
+ assert(s.is_a?(String) && (s =~ /^[\da-z]$/) == 0, 'method expects a lower case alphanumerical char')
75
+ @subfield_data.has_key?(s) ? @subfield_data[s].dup : []
76
+ end
78
77
 
79
- # get a list of the first subfield values for all the codes in the given string
80
- #
81
- # @return [Array] list of the first or only entries of all subfield codes in the input string
82
- # @param s [String] subfield code specification (see match)
83
- #
84
- # The subfield codes are cleaned (see criteria_to_array)
85
- def subfields(s)
86
- assert(s.is_a?(String), 'method expects a string')
87
- return [] unless (match_array = match(s))
88
- criteria_to_array(match_array.join(' ')).collect { |i| send(:subfield, i) }.flatten.compact
89
- end
78
+ # get a list of the first subfield values for all the codes in the given string
79
+ #
80
+ # @return [Array] list of the first or only entries of all subfield codes in the input string
81
+ # @param s [String] subfield code specification (see match)
82
+ #
83
+ # The subfield codes are cleaned (see criteria_to_array)
84
+ def subfields(s)
85
+ assert(s.is_a?(String), 'method expects a string')
86
+ return [] unless (match_array = match(s))
87
+ criteria_to_array(match_array.join(' ')).collect {|i| send(:subfield, i)}.flatten.compact
88
+ end
90
89
 
91
- # get a list of all the subfield values for all the codes in the given string
92
- #
93
- # @return [Array] list of the all the entries of all subfield codes in the input string
94
- # @param s [String] subfield code criteria (see match)
95
- #
96
- # The subfield codes are cleaned (see criteria_to_array)
97
-
98
- def subfields_array(s)
99
- assert(s.is_a?(String), 'method expects a string')
100
- return [] unless (match_array = match(s))
101
- criteria_to_array(match_array.join(' ')).collect { |i| send(:subfield_array, i) }.flatten.compact
102
- end
90
+ # get a list of all the subfield values for all the codes in the given string
91
+ #
92
+ # @return [Array] list of the all the entries of all subfield codes in the input string
93
+ # @param s [String] subfield code criteria (see match)
94
+ #
95
+ # The subfield codes are cleaned (see criteria_to_array)
96
+
97
+ def subfields_array(s)
98
+ assert(s.is_a?(String), 'method expects a string')
99
+ return [] unless (match_array = match(s))
100
+ criteria_to_array(match_array.join(' ')).collect {|i| send(:subfield_array, i)}.flatten.compact
101
+ end
103
102
 
104
- # check if the current VarField matches the given subfield criteria.
105
- #
106
- # @return [String] The matching part(s) of the criteria or nil if no match
107
- # @param criteria [String] subfield criteria: sequence of alternative set of subfield codes that should-shouldn't be present
108
- #
109
- # The subfield criteria consists of groups of characters. At least one of these groups should match for the test to succeed
110
- # Within the group sets of codes may be divided by a hyphen (-). The first set of codes must all be present;
111
- # the second set of codes must all <b>not</b> be present. Either set may be empty.
112
- #
113
- # Examples:
114
- # 'ab' matches '$a...$b...' => ['ab']
115
- # '$a...$b...$c...' => ['ab']
116
- # but not '$a...' => nil # ($b missing)
117
- # '$b...' => nil # ($a missing)
118
- # 'a b' matches '$a...' => ['a']
119
- # '$b...' => ['b']
120
- # '$a...$b...' => ['a', 'b']
121
- # '$a...$b...$c...' => ['a', 'b']
122
- # but not '$c...' => nil # ($a or $b must be present)
123
- # 'abc-d' matches '$a..,$b...$c...' => ['abc-d']
124
- # '$a..,$b...$c...$e...' => ['abc-d']
125
- # but not '$a...$b...$e...' => nil # ($c missing)
126
- # '$a...$b...$c...$d...' => nil # ($d should not be present)
127
- # 'a-b b-a' matches '$a...' => ['a-b']
128
- # '$a...$c...' => ['a-b']
129
- # '$b...' => ['b-a']
130
- # '$b...$c...' => ['b-a']
131
- # but not '$a...$b...' => nil
132
- # 'a-b c-d' matches '$a...' => ['a-b']
133
- # '$a...$c...' => ['a-b', 'c-d']
134
- # '$a...$b...$c...' => ['c-d']
135
- # '$b...$c...' => ['c-d']
136
- # but not '$a...$b...' => nil
137
- # '$c...$d...' => nil
138
- # '$b...$c...$d...' => nil
139
- # '$a...$b...$c...$d...' => nil
140
- def match(criteria)
141
- begin
142
- parser = Libis::Tools::Metadata::SubfieldCriteriaParser.new
143
- tree = parser.parse(criteria)
144
- return [] if tree.is_a? String
145
- tree = [tree] unless tree.is_a? Array
146
- result = tree.map do |selection|
147
- next unless parser.match_selection(selection, keys)
148
- parser.selection_to_s(selection)
149
- end.compact
150
- return nil if result.empty?
151
- result
152
- rescue Parslet::ParseFailed => failure
153
- failure.cause.set_label(criteria)
154
- raise failure
155
- end
103
+ # check if the current VarField matches the given subfield criteria.
104
+ #
105
+ # @return [String] The matching part(s) of the criteria or nil if no match
106
+ # @param criteria [String] subfield criteria: sequence of alternative set of subfield codes that should-shouldn't be present
107
+ #
108
+ # The subfield criteria consists of groups of characters. At least one of these groups should match for the test to succeed
109
+ # Within the group sets of codes may be divided by a hyphen (-). The first set of codes must all be present;
110
+ # the second set of codes must all <b>not</b> be present. Either set may be empty.
111
+ #
112
+ # Examples:
113
+ # 'ab' matches '$a...$b...' => ['ab']
114
+ # '$a...$b...$c...' => ['ab']
115
+ # but not '$a...' => nil # ($b missing)
116
+ # '$b...' => nil # ($a missing)
117
+ # 'a b' matches '$a...' => ['a']
118
+ # '$b...' => ['b']
119
+ # '$a...$b...' => ['a', 'b']
120
+ # '$a...$b...$c...' => ['a', 'b']
121
+ # but not '$c...' => nil # ($a or $b must be present)
122
+ # 'abc-d' matches '$a..,$b...$c...' => ['abc-d']
123
+ # '$a..,$b...$c...$e...' => ['abc-d']
124
+ # but not '$a...$b...$e...' => nil # ($c missing)
125
+ # '$a...$b...$c...$d...' => nil # ($d should not be present)
126
+ # 'a-b b-a' matches '$a...' => ['a-b']
127
+ # '$a...$c...' => ['a-b']
128
+ # '$b...' => ['b-a']
129
+ # '$b...$c...' => ['b-a']
130
+ # but not '$a...$b...' => nil
131
+ # 'a-b c-d' matches '$a...' => ['a-b']
132
+ # '$a...$c...' => ['a-b', 'c-d']
133
+ # '$a...$b...$c...' => ['c-d']
134
+ # '$b...$c...' => ['c-d']
135
+ # but not '$a...$b...' => nil
136
+ # '$c...$d...' => nil
137
+ # '$b...$c...$d...' => nil
138
+ # '$a...$b...$c...$d...' => nil
139
+ def match(criteria)
140
+ begin
141
+ parser = Libis::Metadata::Parser::SubfieldCriteriaParser.new
142
+ tree = parser.parse(criteria)
143
+ return [] if tree.is_a? String
144
+ tree = [tree] unless tree.is_a? Array
145
+ result = tree.map do |selection|
146
+ next unless parser.match_selection(selection, keys)
147
+ parser.selection_to_s(selection)
148
+ end.compact
149
+ return nil if result.empty?
150
+ result
151
+ rescue Parslet::ParseFailed => failure
152
+ failure.cause.set_label(criteria)
153
+ raise failure
156
154
  end
155
+ end
157
156
 
158
- private
157
+ private
159
158
 
160
- # @return [Array] cleaned up version of the input string
161
- # @param subfields [String] subfield code specification
162
- # cleans the subfield code specification and splits it into an array of characters
163
- # Duplicates will be removed from the array and the order will be untouched.
164
- def criteria_to_array(subfields)
159
+ # @return [Array] cleaned up version of the input string
160
+ # @param subfields [String] subfield code specification
161
+ # cleans the subfield code specification and splits it into an array of characters
162
+ # Duplicates will be removed from the array and the order will be untouched.
163
+ def criteria_to_array(subfields)
165
164
 
166
- # note that we remove the '-xxx' part as it is only required for matching
167
- subfields.gsub(/ |-\w*/, '').split('').uniq
168
- end
165
+ # note that we remove the '-xxx' part as it is only required for matching
166
+ subfields.gsub(/ |-\w*/, '').split('').uniq
167
+ end
169
168
 
170
- def sort_helper(x)
171
- # make sure that everything below 'A' is higher than 'z'
172
- # note that this only works for numbers, but that is fine in our case.
173
- x < 'A' ? (x.to_i + 123).chr : x
174
- end
169
+ def sort_helper(x)
170
+ # make sure that everything below 'A' is higher than 'z'
171
+ # note that this only works for numbers, but that is fine in our case.
172
+ x < 'A' ? (x.to_i + 123).chr : x
173
+ end
175
174
 
176
- # implementation for methods for retrieving subfield values
177
- #
178
- # The methods start with a single character: the operation
179
- # 'f' for retrieving only the first occurence of the subfield
180
- # 'a' for retrieving all the subfield values for each of the given subfields
181
- # if omitted, 'f' is assumed
182
- #
183
- # Then a '_' acts as a subdivider between the operation and the subfield(s). It must always be present, even
184
- # if the operation is omitted.
185
- #
186
- # The last past is a sequence of subfield codes that should be used for selecting the values. The order in which the
187
- # subfields are listed is respected in the resulting array of values.
188
- #
189
- # Examples:
190
- #
191
- # t = VarField.new('100', '', '',
192
- # { 'a' => %w'Name NickName',
193
- # 'b' => %w'LastName MaidenName',
194
- # 'c' => %w'eMail',
195
- # '1' => %w'Age',
196
- # '9' => %w'Score'})
197
- #
198
- # # >> 100##$aName$aNickName$bLastName$bMaidenName$ceMail$1Age$9Score <<
199
- #
200
- # t._1ab => ['Age', 'Name', 'LastName']
201
- # # equivalent to: t.f_1av or t.fields('1ab')
202
- #
203
- # t.a_9ab => ['Score', 'Name', 'NickName', 'LastName', 'MaidenName']
204
- # # equivalent to: t.fields_array('9ab')
205
- #
206
- # Note that it is not possible to use a fieldspec for the sequence of subfield codes. Spaces and '-' are not allowed
207
- # in method calls. If you want this, use the #subfield(s) and #subfield(s)_array methods.
208
- #
209
- def method_missing(name, *args)
210
- operation, subfields = name.to_s.split('_')
211
- assert(subfields.size > 0, 'need to specify at least one subfield')
212
- operation = 'f' if operation.empty?
213
- # convert subfield list to fieldspec
214
- subfields = subfields.split('').join(' ')
215
- case operation
216
- when 'f'
217
- if subfields.size > 1
218
- operation = :subfields
219
- else
220
- operation = :subfield
221
- end
222
- when 'a'
223
- if subfields.size > 1
224
- operation = :subfields_array
225
- else
226
- operation = :subfield_array
227
- end
228
- else
229
- throw "Unknown method invocation: '#{name}' with: #{args}"
175
+ # implementation for methods for retrieving subfield values
176
+ #
177
+ # The methods start with a single character: the operation
178
+ # 'f' for retrieving only the first occurence of the subfield
179
+ # 'a' for retrieving all the subfield values for each of the given subfields
180
+ # if omitted, 'f' is assumed
181
+ #
182
+ # Then a '_' acts as a subdivider between the operation and the subfield(s). It must always be present, even
183
+ # if the operation is omitted.
184
+ #
185
+ # The last past is a sequence of subfield codes that should be used for selecting the values. The order in which the
186
+ # subfields are listed is respected in the resulting array of values.
187
+ #
188
+ # Examples:
189
+ #
190
+ # t = VarField.new('100', '', '',
191
+ # { 'a' => %w'Name NickName',
192
+ # 'b' => %w'LastName MaidenName',
193
+ # 'c' => %w'eMail',
194
+ # '1' => %w'Age',
195
+ # '9' => %w'Score'})
196
+ #
197
+ # # >> 100##$aName$aNickName$bLastName$bMaidenName$ceMail$1Age$9Score <<
198
+ #
199
+ # t._1ab => ['Age', 'Name', 'LastName']
200
+ # # equivalent to: t.f_1av or t.fields('1ab')
201
+ #
202
+ # t.a_9ab => ['Score', 'Name', 'NickName', 'LastName', 'MaidenName']
203
+ # # equivalent to: t.fields_array('9ab')
204
+ #
205
+ # Note that it is not possible to use a fieldspec for the sequence of subfield codes. Spaces and '-' are not allowed
206
+ # in method calls. If you want this, use the #subfield(s) and #subfield(s)_array methods.
207
+ #
208
+ def method_missing(name, *args)
209
+ operation, subfields = name.to_s.split('_')
210
+ assert(subfields.size > 0, 'need to specify at least one subfield')
211
+ operation = 'f' if operation.empty?
212
+ # convert subfield list to fieldspec
213
+ subfields = subfields.split('').join(' ')
214
+ case operation
215
+ when 'f'
216
+ if subfields.size > 1
217
+ operation = :subfields
218
+ else
219
+ operation = :subfield
230
220
  end
231
- send(operation, subfields)
232
- end
233
-
234
- def to_ary
235
- nil
221
+ when 'a'
222
+ if subfields.size > 1
223
+ operation = :subfields_array
224
+ else
225
+ operation = :subfield_array
226
+ end
227
+ else
228
+ throw "Unknown method invocation: '#{name}' with: #{args}"
236
229
  end
230
+ send(operation, subfields)
231
+ end
237
232
 
233
+ def to_ary
234
+ nil
238
235
  end
239
236
 
240
237
  end
238
+
241
239
  end
242
- end
240
+ end