libis-tools 0.9.9 → 0.9.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -2
  3. data/README.md +19 -0
  4. data/lib/libis/tools.rb +1 -0
  5. data/lib/libis/tools/config_file.rb +1 -1
  6. data/lib/libis/tools/extend/kernel.rb +16 -0
  7. data/lib/libis/tools/metadata.rb +20 -0
  8. data/lib/libis/tools/metadata/dublin_core_record.rb +1 -1
  9. data/lib/libis/tools/metadata/{field_spec.rb → field_format.rb} +7 -7
  10. data/lib/libis/tools/metadata/fix_field.rb +6 -1
  11. data/lib/libis/tools/metadata/mapper.rb +80 -0
  12. data/lib/libis/tools/metadata/mappers/flandrica.rb +69 -0
  13. data/lib/libis/tools/metadata/mappers/kuleuven.rb +1702 -0
  14. data/lib/libis/tools/metadata/marc21_record.rb +5 -4
  15. data/lib/libis/tools/metadata/marc_record.rb +96 -37
  16. data/lib/libis/tools/metadata/parser/basic_parser.rb +118 -0
  17. data/lib/libis/tools/metadata/parser/dublin_core_parser.rb +36 -0
  18. data/lib/libis/tools/metadata/parser/marc21_parser.rb +206 -0
  19. data/lib/libis/tools/metadata/parser/marc_format_parser.rb +52 -0
  20. data/lib/libis/tools/metadata/parser/marc_rules.rb +35 -0
  21. data/lib/libis/tools/metadata/parser/marc_select_parser.rb +25 -0
  22. data/lib/libis/tools/metadata/parser/patch.rb +21 -0
  23. data/lib/libis/tools/metadata/parser/subfield_criteria_parser.rb +71 -0
  24. data/lib/libis/tools/metadata/parsers.rb +12 -0
  25. data/lib/libis/tools/metadata/var_field.rb +57 -47
  26. data/lib/libis/tools/parameter.rb +12 -2
  27. data/lib/libis/tools/version.rb +1 -1
  28. data/libis-tools.gemspec +4 -3
  29. data/spec/config_spec.rb +3 -1
  30. data/spec/data/MetadataMapping.xlsx +0 -0
  31. data/spec/metadata/8389207.marc +96 -0
  32. data/spec/metadata/dublin_core_parser_spec.rb +48 -0
  33. data/spec/metadata/marc21_parser_data.rb +382 -0
  34. data/spec/metadata/marc21_parser_spec.rb +67 -0
  35. data/spec/metadata/marc21_spec.rb +116 -0
  36. data/spec/metadata/metadata_mapper_spec.rb +23 -0
  37. data/spec/spec_helper.rb +13 -0
  38. data/test.rb +61 -0
  39. metadata +77 -7
  40. data/lib/libis/tools/dc_record.rb +0 -47
@@ -14,7 +14,7 @@ module Libis
14
14
 
15
15
  def get_all_records
16
16
 
17
- @all_records = Hash.new { |h, k| h[k] = [] }
17
+ @all_records.clear
18
18
 
19
19
  @node.xpath('.//leader').each { |f|
20
20
  @all_records['LDR'] << FixField.new('LDR', f.content)
@@ -31,10 +31,11 @@ module Libis
31
31
  tag = v['tag']
32
32
  tag = '%03d' % tag.to_i if tag.size < 3
33
33
 
34
- subfields = Hash.new { |h, k| h[k] = [] }
35
- v.xpath('.//subfield').each { |s| subfields[s['code']] << CGI::escapeHTML(s.content) }
34
+ varfield = VarField.new(tag, v['ind1'].to_s, v['ind2'].to_s)
36
35
 
37
- @all_records[tag] << VarField.new(tag, v['ind1'].to_s, v['ind2'].to_s, subfields)
36
+ v.xpath('.//subfield').each { |s| varfield.add_subfield(s['code'], CGI::escapeHTML(s.content)) }
37
+
38
+ @all_records[tag] << varfield
38
39
 
39
40
  }
40
41
 
@@ -8,58 +8,105 @@ require 'libis/tools/assert'
8
8
 
9
9
  require_relative 'fix_field'
10
10
  require_relative 'var_field'
11
- require_relative 'field_spec'
11
+ require_relative 'field_format'
12
12
 
13
13
  module Libis
14
14
  module Tools
15
15
  module Metadata
16
16
 
17
17
  # noinspection RubyTooManyMethodsInspection
18
+
19
+ # Base class for reading MARC based records.
20
+ #
21
+ # For indicator selection: '#' or '' (empty) is wildcard; '_' or ' ' (space) is blank.
18
22
  class MarcRecord
19
23
 
24
+ # Create a new MarcRecord object
25
+ #
26
+ # @param [XML node] xml_node XML node from Nokogiri or XmlDocument that contains child nodes with the data for
27
+ # one MARC record.
20
28
  def initialize(xml_node)
21
29
  @node = xml_node
30
+ @node.document.remove_namespaces!
31
+ @all_records = Hash.new { |h, k| h[k] = Array.new }
22
32
  end
23
33
 
34
+ # Access to the XML node that was supplied to the constructor
35
+ # @return [XML node]
24
36
  def to_raw
25
37
  @node
26
38
  end
27
39
 
40
+ # Returns the internal data structure (a Hash) with all the MARC data.
41
+ #
42
+ # The internal structure is a Hash with the tag as key and as value an Array of either FixField or VarField
43
+ # instances.
44
+ #
45
+ # @return [Hash] internal data structure
28
46
  def all
29
- # noinspection RubyResolve
30
- @all_records ||= get_all_records
47
+ return @all_records unless @all_records.empty?
48
+ @all_records = get_all_records
31
49
  end
32
50
 
51
+ # Iterates over all the MARC fields.
52
+ #
53
+ # If a block is supplied it will be called for each field in the MARC record. The supplied argument will be the
54
+ # FixField or VarField instance for each field.
55
+ #
56
+ # @return [Array] The list of the field data or return values for each block call.
33
57
  def each
34
- all.each do |k, v|
35
- yield k, v
58
+ all.map { |_, field_array| field_array }.flatten.map do |field|
59
+ block_given? ? yield(field) : field
36
60
  end
37
61
  end
38
62
 
39
- def all_tags(tag, subfields = '')
40
- tag_, ind1, ind2 = tag =~ /^\d{3}/ ? [tag[0..2], tag[3], tag[4]] : [tag, nil, nil]
41
- result = get_records(tag_, ind1, ind2, subfields)
63
+ # Get all fields matching search criteria.
64
+ #
65
+ # A block with one parameter can be supplied when calling this method. Each time a match is found, the block
66
+ # will be called with the field data as argument and the return value of the block will be added to the method's
67
+ # return value. This could for example be used to narrow the selection of the fields:
68
+ #
69
+ # # Only select 700 tags where $4 subfield contains 'abc', 'def' or 'xyz'
70
+ # record.all_tags('700') { |v| v.subfield['4'] =~ /^(abc|def|xyz)$/ ? v : nil }.compact
71
+ #
72
+ # @param [String] tag Tag selection string. Tag name with indicators, '#' for wildcard, '_' for blank. If an
73
+ # extra subfield name is added, a result will be created for each instance found of that subfield.
74
+ # @param [String] subfields Subfield specification. See FieldFormat class for more info; ignored for controlfields.
75
+ # @param [Proc] select_block block that will be executed once for each field found. The block takes one argument
76
+ # (the field) and should return true or false. True selects the field, false rejects it.
77
+ # @return [Array] If a block was supplied to the method call, the array will contain the result of the block
78
+ # for each tag found. Otherwise the array will just contain the data for each matching tag.
79
+ def all_tags(tag, subfields = '', select_block = Proc.new { |_| true})
80
+ t, ind1, ind2, subfield = tag =~ /^\d{3}/ ? [tag[0..2], tag[3], tag[4], tag[5]] : [tag, nil, nil, nil]
81
+ result = get_records(t, ind1, ind2, subfield, subfields, &select_block)
42
82
  return result unless block_given?
43
83
  result.map { |record| yield record }
44
- result.size > 0
45
84
  end
46
85
 
47
- def first_tag(t, subfields = '')
48
- result = all_tags(t, subfields).first
49
- return result unless block_given?
50
- return false unless result
51
- yield result
52
- true
86
+ alias_method :each_tag, :all_tags
87
+
88
+ def select_fields(tag, select_block = nil, &block)
89
+ all_tags(tag, nil, select_block, &block)
53
90
  end
54
91
 
55
- def each_tag(t, s = '')
56
- all_tags(t, s).each do |record|
57
- yield record
58
- end
92
+ # Find the first field matching the criteria.
93
+ #
94
+ # If a block is supplied, it will be called with the found field data. The return value will be whatever the
95
+ # block returns. If no block is supplied, the field data will be returned. If nothing was found, the return
96
+ # value is nil.
97
+ #
98
+ # @param [String] tag Tag selection string. Tag name with indicators, '#' for wildcard, '_' for blank.
99
+ # @param [String] subfields Subfield specification. See FieldFormat class for more info; ignored for controlfields.
100
+ # @return [Object] nil if nothing found; field data or whatever block returns.
101
+ def first_tag(tag, subfields = '')
102
+ result = all_tags(tag, subfields).first
103
+ return nil unless result
104
+ return result unless block_given?
105
+ yield result
59
106
  end
60
107
 
61
- def all_fields(t, s)
62
- r = all_tags(t, s).collect { |tag| tag.fields_array(s) }.flatten.compact
108
+ def all_fields(tag, subfields)
109
+ r = all_tags(tag, subfields).collect { |tag| tag.subfields_array(subfields) }.flatten.compact
63
110
  return r unless block_given?
64
111
  r.map { |field| yield field }
65
112
  r.size > 0
@@ -116,11 +163,11 @@ module Libis
116
163
  record = ''
117
164
  doc_number = tag('001').datas
118
165
 
119
- all.select { |t| t.is_a? FixField }.each { |t| record += "#{format('%09s', doc_number)} #{t.tag} L #{t.datas}\n" }
120
- all.select { |t| t.is_a? VarField }.each { |t|
166
+ all.select { |t| t.is_a? Libis::Tools::Metadata::FixField }.each { |t| record += "#{format('%09s', doc_number)} #{t.tag} L #{t.datas}\n" }
167
+ all.select { |t| t.is_a? Libis::Tools::Metadata::VarField }.each { |t|
121
168
  record += "#{format('%09s', doc_number)} #{t.tag}#{t.ind1}#{t.ind2} L "
122
169
  t.keys.each { |k|
123
- t.field_array(k).each { |f|
170
+ t.subfield_array(k).each { |f|
124
171
  record += "$$#{k}#{CGI::unescapeHTML(f)}"
125
172
  }
126
173
  }
@@ -134,37 +181,37 @@ module Libis
134
181
 
135
182
  def element(*parts)
136
183
  opts = options parts
137
- field_spec(opts, *parts)
184
+ field_format(opts, *parts)
138
185
  end
139
186
 
140
187
  def list_s(*parts)
141
188
  opts = options parts, join: ' '
142
- field_spec(opts, *parts)
189
+ field_format(opts, *parts)
143
190
  end
144
191
 
145
192
  def list_c(*parts)
146
193
  opts = options parts, join: ', '
147
- field_spec(opts, *parts)
194
+ field_format(opts, *parts)
148
195
  end
149
196
 
150
197
  def list_d(*parts)
151
198
  opts = options parts, join: ' - '
152
- field_spec(opts, *parts)
199
+ field_format(opts, *parts)
153
200
  end
154
201
 
155
202
  def repeat(*parts)
156
203
  opts = options parts, join: '; '
157
- field_spec(opts, *parts)
204
+ field_format(opts, *parts)
158
205
  end
159
206
 
160
207
  def opt_r(*parts)
161
208
  opts = options parts, fix: '()'
162
- field_spec(opts, *parts)
209
+ field_format(opts, *parts)
163
210
  end
164
211
 
165
212
  def opt_s(*parts)
166
213
  opts = options parts, fix: '[]'
167
- field_spec(opts, *parts)
214
+ field_format(opts, *parts)
168
215
  end
169
216
 
170
217
  def odis_link(group, id, label)
@@ -177,11 +224,11 @@ module Libis
177
224
  default.merge(args.last.is_a?(::Hash) ? args.pop : {})
178
225
  end
179
226
 
180
- def field_spec(default_options, *parts)
181
- FieldSpec.new(*parts).add_default_options(default_options).to_s
227
+ def field_format(default_options, *parts)
228
+ Libis::Tools::Metadata::FieldFormat.new(*parts).add_default_options(default_options).to_s
182
229
  end
183
230
 
184
- def get_records(tag, ind1 = '', ind2 = '', subfields = '')
231
+ def get_records(tag, ind1 = '', ind2 = '', subfield = nil, subfields = '', &block)
185
232
 
186
233
  ind1 ||= ''
187
234
  ind2 ||= ''
@@ -193,14 +240,26 @@ module Libis
193
240
  ind2.tr!('_', ' ')
194
241
  ind2.tr!('#', '')
195
242
 
196
- all[tag].select do |v|
197
- v.is_a?(FixField) ||
243
+ found = all[tag].select do |v|
244
+ result = v.is_a?(Libis::Tools::Metadata::FixField) ||
198
245
  ((ind1.empty? or v.ind1 == ind1) &&
199
246
  (ind2.empty? or v.ind2 == ind2) &&
200
- v.match_fieldspec?(subfields)
247
+ v.match(subfields)
201
248
  )
249
+ result &&= block.call(v) if block
250
+ result
202
251
  end
203
252
 
253
+ return found unless subfield
254
+
255
+ # duplicate tags for subfield instances
256
+ found.map do |field|
257
+ next unless field.is_a? Libis::Tools::Metadata::FixField
258
+ field.subfield_data[subfield].map do |sfield|
259
+ field.dup.subfield_data[subfield] = [sfield]
260
+ end
261
+ end.compact.flatten
262
+
204
263
  end
205
264
 
206
265
  end
@@ -0,0 +1,118 @@
1
+ # encoding: utf-8
2
+
3
+ require 'parslet'
4
+ require 'parslet/convenience'
5
+
6
+ module Libis
7
+ module Tools
8
+ module Metadata
9
+ # noinspection RubyResolve
10
+ class BasicParser < Parslet::Parser
11
+ # space
12
+ rule(:space) { match('\s') }
13
+ rule(:space?) { space.maybe }
14
+ rule(:spaces) { space.repeat(1) }
15
+ rule(:spaces?) { space.repeat }
16
+
17
+ # numbers
18
+ rule(:number) { match('[0-9]') }
19
+ rule(:number?) { number.maybe }
20
+ rule(:integer) { number.repeat(1) }
21
+
22
+ # chars
23
+ rule(:character) { match(/[a-z]/i) }
24
+ rule(:character?) { character.maybe }
25
+ rule(:characters) { character.repeat(1) }
26
+
27
+ # word
28
+ rule(:wordchar) { match('\w') }
29
+
30
+ # name
31
+ rule(:name_string) { ((character | underscore) >> wordchar.repeat).repeat(1) }
32
+
33
+ # text
34
+ rule(:other) { not_paren }
35
+ rule(:text) { other.repeat(1) }
36
+ rule(:text?) { text.maybe }
37
+
38
+ # special chars
39
+ rule(:minus) { str('-') }
40
+ rule(:colon) { str(':') }
41
+ rule(:semicolon) { str(';') }
42
+ rule(:underscore) { str('_') }
43
+ rule(:hashtag) { str('#') }
44
+ rule(:dollar) { str('$') }
45
+ rule(:star) { str('*') }
46
+
47
+ # grouping
48
+ rule(:paren) { lparen | rparen }
49
+ rule(:lparen) { lrparen | lsparen | lcparen | squote | dquote }
50
+ rule(:rparen) { rrparen | rsparen | rcparen | squote | dquote }
51
+
52
+ rule(:not_paren) { paren.absent? >> any }
53
+ rule(:not_lparen) { lrparen.absent? >> lsparen.absent? >> lcparen.absent? >> squote.absent? >> dquote.absent? >> any }
54
+ rule(:not_rparen) { rrparen.absent? >> rsparen.absent? >> rcparen.absent? >> squote.absent? >> dquote.absent? >> any }
55
+
56
+ rule(:lrparen) { str('(') }
57
+ rule(:lsparen) { str('[') }
58
+ rule(:lcparen) { str('{') }
59
+ rule(:rrparen) { str(')') }
60
+ rule(:rsparen) { str(']') }
61
+ rule(:rcparen) { str('}') }
62
+
63
+ rule(:squote) { str("'") }
64
+ rule(:dquote) { str('"') }
65
+ rule(:quote) { squote | dquote }
66
+
67
+ rule(:not_squote) { squote.absent? >> any }
68
+ rule(:not_dquote) { dquote.absent? >> any }
69
+ rule(:not_quote) { quote.absent? >> any }
70
+
71
+ def complement(char)
72
+ case char
73
+ when '('
74
+ ')'
75
+ when '{'
76
+ '}'
77
+ when '['
78
+ ']'
79
+ else
80
+ char
81
+ end
82
+ end
83
+
84
+ def grouped(foo, left_paren = lparen)
85
+ scope {
86
+ left_paren.capture(:paren).as(:lparen) >>
87
+ foo >>
88
+ dynamic { |_, c| str(complement(c.captures[:paren])) }.as(:rparen)
89
+ }
90
+ end
91
+
92
+ def grouped_anonymous(foo, left_paren = lparen)
93
+ scope {
94
+ left_paren.capture(:paren) >>
95
+ foo >>
96
+ dynamic { |_, c| str(complement(c.captures[:paren])) }
97
+ }
98
+ end
99
+
100
+ def any_quoted(key = :text)
101
+ scope {
102
+ quote.capture(:quote) >>
103
+ dynamic { |_, c| (str(c.captures[:quote]).absent? >> any).repeat(1) }.maybe.as(key) >>
104
+ dynamic { |_, c| str(c.captures[:quote]) }
105
+ }
106
+ end
107
+
108
+ def transformer
109
+ self.class::Transformer.new rescue nil
110
+ end
111
+
112
+ end
113
+
114
+ end
115
+ end
116
+ end
117
+
118
+
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ require 'parslet'
4
+
5
+ require_relative 'basic_parser'
6
+
7
+ module Libis
8
+ module Tools
9
+ module Metadata
10
+
11
+ # noinspection RubyResolve
12
+ class DublinCoreParser < Libis::Tools::Metadata::BasicParser
13
+ rule(:namespace) { match('[^:]').repeat(1).as(:namespace) >> str(':') }
14
+ rule(:namespace?) { namespace.maybe }
15
+
16
+ rule(:attribute) { namespace? >> name_string.as(:name) >> str('=') >> str('"') >> match('[^"]').repeat(1).as(:value) >> str('"') }
17
+ rule(:attributes) { attribute >> (spaces >> attribute).repeat }
18
+ rule(:attributes?) { attributes.maybe }
19
+ rule(:element) { name_string.as(:element) }
20
+ rule(:DC) { namespace >> element >> (spaces >> attributes.as(:attributes)).maybe }
21
+
22
+ root(:DC)
23
+
24
+ def to_target(tree)
25
+ tree = tree[:DC]
26
+ return nil unless tree
27
+ result = "xml['#{tree[:namespace]}'].#{tree[:element]}("
28
+ tree[:attributes].each { |attribute| result += "'#{attribute[:name]}' => '#{attribute[:value]}'" }
29
+ result + ').text'
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,206 @@
1
+ # encoding: utf-8
2
+
3
+ require 'parslet'
4
+
5
+ require_relative 'basic_parser'
6
+ require_relative 'marc_rules'
7
+
8
+ module Libis
9
+ module Tools
10
+ module Metadata
11
+
12
+ # noinspection RubyResolve
13
+ class Marc21Parser < Libis::Tools::Metadata::BasicParser
14
+
15
+ root(:marc21)
16
+ rule(:marc21) { select.as(:select) | format.as(:format) }
17
+
18
+ # select syntax
19
+ rule(:select) do
20
+ str('MARC') >>
21
+ spaces? >> tag.as(:tag) >>
22
+ spaces? >> indicator.maybe.as(:ind1) >> indicator.maybe.as(:ind2) >>
23
+ spaces? >> subfield.maybe.as(:subfield) >>
24
+ spaces? >> condition.maybe.as(:condition)
25
+ end
26
+ rule(:condition) { grouped_anonymous(cond_format.as(:cond_format)) }
27
+ rule(:cond_format) { cond_entry.repeat(1).maybe.as(:entry) >> postfix.maybe.as(:postfix) }
28
+ rule(:cond_entry) { sf_reference | method_call | cond_group }
29
+ rule(:cond_group) { (prefix.maybe.as(:prefix) >> grouped(cond_format)).as(:cond_group) }
30
+
31
+ # Formatting syntax
32
+ rule(:format) { entry.repeat(1).maybe.as(:entry) >> postfix.maybe.as(:postfix) }
33
+
34
+ rule(:entry) { sf_reference | method_call | group }
35
+ # noinspection RubyArgCount
36
+ rule(:group) { (prefix.maybe.as(:prefix) >> grouped(format)).as(:group) }
37
+ # noinspection RubyArgCount
38
+ rule(:method_call) { (prefix.maybe.as(:prefix) >> sf_indicator >> grouped_anonymous(format, lrparen)).as(:method_call) }
39
+
40
+ # pre- and postfix
41
+ rule(:prefix) { other.repeat(1) }
42
+ rule(:prefix) { text }
43
+ rule(:postfix) { other.repeat(1) }
44
+ rule(:postfix) { text }
45
+
46
+ # subfield reference
47
+ rule(:sf_reference) { sf_variable.as(:subfield) | sf_fixed.as(:fixfield) }
48
+
49
+ rule(:sf_variable) { prefix.maybe.as(:prefix) >> sf_indicator >> sf_repeat.maybe.as(:repeat) >> sf_name }
50
+ rule(:sf_repeat) { star >> any_quoted(:separator).maybe }
51
+
52
+ rule(:sf_fixed) { prefix.maybe.as(:prefix) >> sf_indicator >> lsparen >> (sf_range | sf_position | sf_star) >> rsparen }
53
+ rule(:sf_star) { star.as(:all) }
54
+ rule(:sf_position) { integer.as(:position) }
55
+ rule(:sf_range) { integer.as(:first) >> minus >> integer.as(:last) }
56
+
57
+ rule(:other) { paren.absent? >> dollar.absent? >> any | litteral_dollar }
58
+
59
+ # tag
60
+ rule(:tag) { tag_numeric | tag_alpha }
61
+ rule(:tag_numeric) { number.repeat(3, 3) }
62
+ rule(:tag_alpha) { character.repeat(3, 3) }
63
+
64
+ # indicator
65
+ rule(:indicator) { hashtag | underscore | number | character }
66
+
67
+ # subfield
68
+ rule(:sf_indicator) { dollar }
69
+ rule(:sf_name) { (character | number).as(:name) }
70
+ rule(:sf_names) { (character | number).repeat(1).as(:names) }
71
+ rule(:subfield) { sf_indicator >> sf_name }
72
+ rule(:litteral_dollar) { dollar >> dollar }
73
+
74
+ # noinspection RubyResolve
75
+ class Transformer < Parslet::Transform
76
+ rule(name: simple(:name)) { "#{name}" }
77
+ # select transformation rules
78
+ rule(cond_group: {
79
+ prefix: simple(:prefix),
80
+ lparen: simple(:lparen),
81
+ entry: simple(:entry),
82
+ postfix: simple(:postfix),
83
+ rparen: simple(:rparen)}) {
84
+ "#{prefix}#{lparen}#{entry}#{postfix}#{rparen}"
85
+ }
86
+ rule(cond_group: {
87
+ prefix: simple(:prefix),
88
+ lparen: simple(:lparen),
89
+ entry: sequence(:entry),
90
+ postfix: simple(:postfix),
91
+ rparen: simple(:rparen)}) {
92
+ "#{prefix}#{lparen}#{entry.join}#{postfix}#{rparen}"
93
+ }
94
+ rule(cond_format: {
95
+ entry: sequence(:entry),
96
+ postfix: simple(:postfix)
97
+ }) { ", Proc.new { |f| #{entry.join}#{postfix} }" }
98
+ rule(select: {
99
+ tag: simple(:tag),
100
+ ind1: simple(:ind1),
101
+ ind2: simple(:ind2),
102
+ subfield: simple(:subfield),
103
+ condition: simple(:condition)
104
+ }) { "record.select_fields('#{tag}#{ind1 || '#'}#{ind2 || '#'}#{subfield}'#{condition || ''})" }
105
+ # format transformation rules
106
+ rule(format: {
107
+ entry: sequence(:entries),
108
+ postfix: simple(:postfix)
109
+ }) do
110
+ if entries.size == 1 && postfix.nil?
111
+ entries.first
112
+ else
113
+ "field_format(#{entries.join(',')}#{", postfix: '#{postfix}'" if postfix}).to_s"
114
+ end
115
+ end
116
+ rule(group: {
117
+ prefix: simple(:prefix),
118
+ lparen: simple(:lparen),
119
+ entry: nil,
120
+ postfix: simple(:postfix),
121
+ rparen: simple(:rparen)}) {
122
+ "#{prefix}#{lparen}#{postfix}#{rparen}"
123
+ }
124
+ rule(group: {
125
+ prefix: simple(:prefix),
126
+ lparen: simple(:lparen),
127
+ entry: '',
128
+ postfix: simple(:postfix),
129
+ rparen: simple(:rparen)}) {
130
+ "#{prefix}#{lparen}#{postfix}#{rparen}"
131
+ }
132
+ rule(group: {
133
+ prefix: simple(:prefix),
134
+ lparen: simple(:lparen),
135
+ entry: simple(:entry),
136
+ postfix: simple(:postfix),
137
+ rparen: simple(:rparen)}) {
138
+ "field_format(#{entry}#{", prefix: '#{prefix}#{lparen}'" if prefix || lparen}#{", postfix: '#{postfix}#{rparen}'" if postfix || rparen}).to_s"
139
+ }
140
+ rule(group: {
141
+ prefix: simple(:prefix),
142
+ lparen: simple(:lparen),
143
+ entry: sequence(:entries),
144
+ postfix: simple(:postfix),
145
+ rparen: simple(:rparen)}) {
146
+ "field_format(#{entries.join(',')}#{", prefix: '#{prefix}#{lparen}'" if prefix || lparen}#{", postfix: '#{postfix}#{rparen}'" if postfix || rparen}).to_s"
147
+ }
148
+ rule(fixfield: {
149
+ prefix: nil,
150
+ all: '*'
151
+ }) { 'f[]' }
152
+ rule(fixfield: {
153
+ prefix: simple(:prefix),
154
+ all: '*'
155
+ }) { "field_format(f[], prefix: '#{prefix}').to_s" }
156
+ rule(fixfield: {
157
+ prefix: nil,
158
+ position: simple(:position)
159
+ }) { "f[#{position}]" }
160
+ rule(fixfield: {
161
+ prefix: simple(:prefix),
162
+ position: simple(:position)
163
+ }) do
164
+ if prefix
165
+ "field_format(f[#{position}], prefix: '#{prefix}').to_s"
166
+ else
167
+ "f[#{position}]"
168
+ end
169
+ end
170
+ rule(fixfield: {
171
+ prefix: nil,
172
+ first: simple(:from),
173
+ last: simple(:to)
174
+ }) { "f[#{from},#{to}]" }
175
+ rule(fixfield: {
176
+ prefix: simple(:prefix),
177
+ first: simple(:from),
178
+ last: simple(:to)
179
+ }) { "field_format(f[#{from},#{to}], prefix: '#{prefix}').to_s" }
180
+ rule(subfield: {
181
+ prefix: simple(:prefix),
182
+ repeat: nil,
183
+ name: simple(:name),
184
+ }) { "field_format(f.subfield('#{name}'), prefix: '#{prefix}').to_s" }
185
+ rule(subfield: {
186
+ prefix: simple(:prefix),
187
+ repeat: {separator: simple(:separator)},
188
+ name: simple(:name),
189
+ }) { "field_format(f.subfield_array('#{name}')#{", prefix: '#{prefix}'" if prefix}, join: '#{separator}').to_s" }
190
+ rule(subfield: {
191
+ prefix: simple(:prefix),
192
+ repeat: '*',
193
+ name: simple(:name),
194
+ }) { "field_format(f.subfield_array('#{name}')#{", prefix: '#{prefix}'" if prefix}, join: ';').to_s" }
195
+ rule(subfield: {
196
+ prefix: nil,
197
+ repeat: nil,
198
+ name: simple(:name),
199
+ }) { "f.subfield('#{name}')" }
200
+ end
201
+
202
+ end
203
+
204
+ end
205
+ end
206
+ end