athena 0.0.1.53

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,77 @@
1
+ #--
2
+ ###############################################################################
3
+ # #
4
+ # A component of athena, the database file converter. #
5
+ # #
6
+ # Copyright (C) 2007 University of Cologne, #
7
+ # Albertus-Magnus-Platz, #
8
+ # 50932 Cologne, Germany #
9
+ # #
10
+ # Authors: #
11
+ # Jens Wille <jens.wille@uni-koeln.de> #
12
+ # #
13
+ # athena is free software; you can redistribute it and/or modify it under the #
14
+ # terms of the GNU General Public License as published by the Free Software #
15
+ # Foundation; either version 3 of the License, or (at your option) any later #
16
+ # version. #
17
+ # #
18
+ # athena is distributed in the hope that it will be useful, but WITHOUT ANY #
19
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
20
+ # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more #
21
+ # details. #
22
+ # #
23
+ # You should have received a copy of the GNU General Public License along #
24
+ # with athena. If not, see <http://www.gnu.org/licenses/>. #
25
+ # #
26
+ ###############################################################################
27
+ #++
28
+
29
+ module Athena
30
+
31
+ class Formats
32
+
33
+ @formats = { :in => {}, :out => {} }
34
+
35
+ class << self
36
+
37
+ def formats
38
+ Formats.instance_variable_get :@formats
39
+ end
40
+
41
+ def [](direction, format)
42
+ formats[direction][format]
43
+ end
44
+
45
+ def valid_format?(direction, format)
46
+ formats[direction].has_key? format
47
+ end
48
+
49
+ def convert(*args)
50
+ raise NotImplementedError, 'must be defined by sub-class'
51
+ end
52
+
53
+ private
54
+
55
+ def register_format(direction, format)
56
+ formats[direction][format] = self
57
+ end
58
+
59
+ def register_formats(direction, *formats)
60
+ formats.each { |format|
61
+ register_format(direction, format)
62
+ }
63
+ end
64
+
65
+ end
66
+
67
+ def parse(*args)
68
+ raise NotImplementedError, 'must be defined by sub-class'
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+
75
+ Dir[__FILE__.sub(/\.rb$/, '/**/*.rb')].each { |rb|
76
+ require rb
77
+ }
@@ -0,0 +1,65 @@
1
+ #--
2
+ ###############################################################################
3
+ # #
4
+ # A component of athena, the database file converter. #
5
+ # #
6
+ # Copyright (C) 2007 University of Cologne, #
7
+ # Albertus-Magnus-Platz, #
8
+ # 50932 Cologne, Germany #
9
+ # #
10
+ # Authors: #
11
+ # Jens Wille <jens.wille@uni-koeln.de> #
12
+ # #
13
+ # athena is free software; you can redistribute it and/or modify it under the #
14
+ # terms of the GNU General Public License as published by the Free Software #
15
+ # Foundation; either version 3 of the License, or (at your option) any later #
16
+ # version. #
17
+ # #
18
+ # athena is distributed in the hope that it will be useful, but WITHOUT ANY #
19
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
20
+ # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more #
21
+ # details. #
22
+ # #
23
+ # You should have received a copy of the GNU General Public License along #
24
+ # with athena. If not, see <http://www.gnu.org/licenses/>. #
25
+ # #
26
+ ###############################################################################
27
+ #++
28
+
29
+ require 'iconv'
30
+
31
+ module Athena
32
+
33
+ class Formats
34
+
35
+ class DBM < Athena::Formats
36
+
37
+ register_formats :out, 'dbm', 'midos'
38
+
39
+ CRLF = "\015\012"
40
+
41
+ ICONV_TO_LATIN1 = Iconv.new('latin1', 'utf-8')
42
+
43
+ def self.convert(record)
44
+ dbm = ["ID:#{record.id}"]
45
+ record.struct.each { |field, struct|
46
+ strings = struct[:elements].inject([]) { |array, element|
47
+ values = (struct[:values][element] || []).map { |v|
48
+ (v || '').strip.gsub(/(?:\r?\n)+/, ' ')
49
+ }.reject { |v| v.empty? }
50
+
51
+ array << (values.empty? ? struct[:empty] : values.join('|'))
52
+ }
53
+
54
+ dbm << "#{field.to_s.upcase}:#{ICONV_TO_LATIN1.iconv(struct[:string] % strings)}"
55
+ }
56
+ dbm << '&&&'
57
+
58
+ dbm.join(CRLF) << CRLF << CRLF
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+
65
+ end
@@ -0,0 +1,83 @@
1
+ #--
2
+ ###############################################################################
3
+ # #
4
+ # A component of athena, the database file converter. #
5
+ # #
6
+ # Copyright (C) 2007 University of Cologne, #
7
+ # Albertus-Magnus-Platz, #
8
+ # 50932 Cologne, Germany #
9
+ # #
10
+ # Authors: #
11
+ # Jens Wille <jens.wille@uni-koeln.de> #
12
+ # #
13
+ # athena is free software; you can redistribute it and/or modify it under the #
14
+ # terms of the GNU General Public License as published by the Free Software #
15
+ # Foundation; either version 3 of the License, or (at your option) any later #
16
+ # version. #
17
+ # #
18
+ # athena is distributed in the hope that it will be useful, but WITHOUT ANY #
19
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
20
+ # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more #
21
+ # details. #
22
+ # #
23
+ # You should have received a copy of the GNU General Public License along #
24
+ # with athena. If not, see <http://www.gnu.org/licenses/>. #
25
+ # #
26
+ ###############################################################################
27
+ #++
28
+
29
+ module Athena
30
+
31
+ class Formats
32
+
33
+ class Sisis < Athena::Formats
34
+
35
+ register_format :in, 'sisis'
36
+
37
+ attr_reader :record_element, :config, :parser
38
+
39
+ def initialize(parser)
40
+ config = parser.config.dup
41
+
42
+ case @record_element = config.delete(:__record_element)
43
+ when String
44
+ # fine!
45
+ when nil
46
+ raise NoRecordElementError, 'no record element specified'
47
+ else
48
+ raise IllegalRecordElementError, "illegal record element #{@record_element}"
49
+ end
50
+
51
+ @config = config
52
+ @parser = parser
53
+ end
54
+
55
+ def parse(source)
56
+ record = nil
57
+
58
+ source.each { |line|
59
+ element, value = line.match(/(\d+).*?:\s*(.*)/)[1, 2]
60
+
61
+ case element
62
+ when record_element
63
+ record.close if record
64
+ record = Athena::Record.new(parser.block, value)
65
+ else
66
+ record.update(element, value, config[element])
67
+ end
68
+ }
69
+
70
+ record.close if record
71
+ end
72
+
73
+ class NoRecordElementError < StandardError
74
+ end
75
+
76
+ class IllegalRecordElementError < StandardError
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
83
+ end
@@ -0,0 +1,278 @@
1
+ #--
2
+ ###############################################################################
3
+ # #
4
+ # A component of athena, the database file converter. #
5
+ # #
6
+ # Copyright (C) 2007 University of Cologne, #
7
+ # Albertus-Magnus-Platz, #
8
+ # 50932 Cologne, Germany #
9
+ # #
10
+ # Authors: #
11
+ # Jens Wille <jens.wille@uni-koeln.de> #
12
+ # #
13
+ # athena is free software; you can redistribute it and/or modify it under the #
14
+ # terms of the GNU General Public License as published by the Free Software #
15
+ # Foundation; either version 3 of the License, or (at your option) any later #
16
+ # version. #
17
+ # #
18
+ # athena is distributed in the hope that it will be useful, but WITHOUT ANY #
19
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
20
+ # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more #
21
+ # details. #
22
+ # #
23
+ # You should have received a copy of the GNU General Public License along #
24
+ # with athena. If not, see <http://www.gnu.org/licenses/>. #
25
+ # #
26
+ ###############################################################################
27
+ #++
28
+
29
+ require 'forwardable'
30
+
31
+ require 'rubygems'
32
+
33
+ require 'xmlstreamin'
34
+ require 'nuggets/hash/insert'
35
+
36
+ module Athena
37
+
38
+ class Formats
39
+
40
+ class XML < Athena::Formats
41
+
42
+ include Util
43
+
44
+ register_format :in, 'xml'
45
+
46
+ attr_reader :spec, :listener
47
+
48
+ def initialize(parser)
49
+ @spec = build_spec(parser)
50
+ @listener = XMLStreamin::XMLStreamListener.new(@spec)
51
+ end
52
+
53
+ def parse(source)
54
+ REXML::Document.parse_stream(source, listener)
55
+ end
56
+
57
+ private
58
+
59
+ def build_spec(parser)
60
+ config = parser.config.dup
61
+
62
+ case record_element = config.delete(:__record_element)
63
+ when String
64
+ # fine!
65
+ when nil
66
+ raise NoRecordElementError, 'no record element specified'
67
+ else
68
+ raise IllegalRecordElementError, "illegal record element #{record_element}"
69
+ end
70
+
71
+ element_specs = config.inject({}) { |specs, (element, element_spec)|
72
+ element_spec.each { |field, c|
73
+ element.split('/').reverse.inject({}) { |hash, part|
74
+ s = define_spec(element, field, c, hash.empty? ? :default : hash)
75
+ merge_specs(hash, part, s)
76
+ }.each { |key, s|
77
+ merge_specs(specs, key, s)
78
+ }
79
+ }
80
+
81
+ specs
82
+ }
83
+
84
+ record_spec = RecordSpec.new(parser)
85
+ record_spec.specs!(element_specs)
86
+
87
+ root_spec = BaseSpec.new
88
+ root_spec.specs!(record_element => record_spec)
89
+
90
+ spec = BaseSpec.new
91
+ spec.default!(root_spec)
92
+
93
+ verbose(:spec, BaseSpec) do
94
+ spec.inspect_spec
95
+ end
96
+
97
+ spec
98
+ end
99
+
100
+ def define_spec(element, field, config, arg)
101
+ spec = ElementSpec.new(element, field, config)
102
+
103
+ case arg
104
+ when Hash
105
+ spec.specs!(arg)
106
+ else
107
+ spec.default!(SubElementSpec.new(spec))
108
+ end
109
+
110
+ spec
111
+ end
112
+
113
+ def merge_specs(container, key, spec)
114
+ container.insert!(key, spec) { |s1, s2|
115
+ if s1.respond_to?(:specs!)
116
+ s1.specs!(s2.respond_to?(:specs) ? s2.specs : s2)
117
+ s1
118
+ else
119
+ s1.merge(s2)
120
+ end
121
+ }
122
+ end
123
+
124
+ class BaseSpec < XMLStreamin::XMLSpec
125
+
126
+ include Util
127
+
128
+ @level = 0
129
+
130
+ def start(context, name, attrs)
131
+ verbose(:xml) do
132
+ spit "#{indent(level)}<#{name}>"
133
+ step :down
134
+
135
+ attrs.each { |attr|
136
+ spit "#{indent(level + 1)}[#{attr[0]} = #{attr[1]}]"
137
+ }
138
+ end
139
+
140
+ return context
141
+ end
142
+
143
+ def text(context, data)
144
+ verbose(:xml) do
145
+ content = data.strip
146
+ spit "#{indent(level)}#{content}" unless content.empty?
147
+ end
148
+
149
+ return context
150
+ end
151
+
152
+ def done(context, name)
153
+ verbose(:xml) do
154
+ step :up
155
+ spit "#{indent(level)}</#{name}>"
156
+ end
157
+
158
+ return context
159
+ end
160
+
161
+ def empty(context)
162
+ verbose(:xml) do
163
+ step :up
164
+ end
165
+
166
+ return context
167
+ end
168
+
169
+ def inspect_spec(element = nil, level = 0)
170
+ if respond_to?(:field)
171
+ msg = "#{indent(level)}[#{element}] #{field.to_s.upcase} -> #{name}"
172
+ respond_to?(:spit) ? spit(msg) : warn(msg)
173
+ specs.each { |e, s|
174
+ s.inspect_spec(e, level + 1)
175
+ }
176
+ else
177
+ if specs.empty?
178
+ specs.default.inspect_spec('?', level)
179
+ else
180
+ specs.each { |e, s|
181
+ s.inspect_spec(e, level)
182
+ }
183
+ end
184
+ end
185
+ end
186
+
187
+ private
188
+
189
+ def level
190
+ BaseSpec.instance_variable_get :@level
191
+ end
192
+
193
+ def step(direction)
194
+ steps = { :down => 1, :up => -1 }
195
+ BaseSpec.instance_variable_set :@level, level + steps[direction]
196
+ end
197
+
198
+ end
199
+
200
+ class RecordSpec < BaseSpec
201
+
202
+ attr_reader :parser
203
+ attr_accessor :record
204
+
205
+ def initialize(parser)
206
+ super()
207
+
208
+ @parser = parser
209
+ end
210
+
211
+ def start(context, name, attrs)
212
+ super
213
+
214
+ self.record = Athena::Record.new(parser.block)
215
+ end
216
+
217
+ def done(context, name)
218
+ super
219
+
220
+ record.close
221
+ end
222
+
223
+ end
224
+
225
+ class ElementSpec < BaseSpec
226
+
227
+ attr_reader :name, :field, :config
228
+ attr_accessor :record
229
+
230
+ def initialize(name, field, config)
231
+ super()
232
+
233
+ @name = name
234
+ @field = field
235
+ @config = config
236
+ end
237
+
238
+ def start(context, name, attrs)
239
+ super
240
+
241
+ self.record = Athena::Record[field, config]
242
+ end
243
+
244
+ def text(context, data)
245
+ super
246
+
247
+ record.update name, data
248
+ end
249
+
250
+ end
251
+
252
+ class SubElementSpec < BaseSpec
253
+
254
+ extend Forwardable
255
+
256
+ # Forward to parent element; need to specify *all* its attributes and methods
257
+ def_delegators :@parent, :name, :field, :config, :record, :start, :text
258
+
259
+ def initialize(parent)
260
+ super()
261
+
262
+ @parent = parent
263
+ default! self
264
+ end
265
+
266
+ end
267
+
268
+ class NoRecordElementError < StandardError
269
+ end
270
+
271
+ class IllegalRecordElementError < StandardError
272
+ end
273
+
274
+ end
275
+
276
+ end
277
+
278
+ end