midos 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog ADDED
@@ -0,0 +1,11 @@
1
+ # markup: rd
2
+
3
+ = Revision history for midos
4
+
5
+ == 0.0.1 [2014-04-11]
6
+
7
+ * First release (extracted from ruby-nuggets).
8
+
9
+ == 0.0.0 [2014-04-09]
10
+
11
+ * Birthday :-)
data/README ADDED
@@ -0,0 +1,42 @@
1
+ = midos - A Ruby client for MIDOS databases
2
+
3
+ == VERSION
4
+
5
+ This documentation refers to midos version 0.0.1
6
+
7
+
8
+ == DESCRIPTION
9
+
10
+ Provides both read and write access for the flat file databases of MIDOS 2000
11
+ and MIDOS 6 as well as MIDOS Thesaurus.
12
+
13
+
14
+ == LINKS
15
+
16
+ PROGRIS MIDOS:: http://progris.de/produkte.htm
17
+ Documentation:: https://blackwinter.github.io/midos/
18
+ Source code:: https://github.com/blackwinter/midos
19
+ RubyGem:: https://rubygems.org/gems/midos
20
+
21
+
22
+ == AUTHORS
23
+
24
+ * Jens Wille <mailto:jens.wille@gmail.com>
25
+
26
+
27
+ == LICENSE AND COPYRIGHT
28
+
29
+ Copyright (C) 2014 Jens Wille
30
+
31
+ midos is free software: you can redistribute it and/or modify it
32
+ under the terms of the GNU Affero General Public License as published by
33
+ the Free Software Foundation, either version 3 of the License, or (at your
34
+ option) any later version.
35
+
36
+ midos is distributed in the hope that it will be useful, but
37
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
38
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
39
+ License for more details.
40
+
41
+ You should have received a copy of the GNU Affero General Public License
42
+ along with midos. If not, see <http://www.gnu.org/licenses/>.
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require File.expand_path(%q{../lib/midos/version}, __FILE__)
2
+
3
+ begin
4
+ require 'hen'
5
+
6
+ Hen.lay! {{
7
+ gem: {
8
+ name: %q{midos},
9
+ version: Midos::VERSION,
10
+ summary: %q{A Ruby client for MIDOS databases.},
11
+ description: %q{Access PROGRIS MIDOS databases from Ruby.},
12
+ author: %q{Jens Wille},
13
+ email: %q{jens.wille@gmail.com},
14
+ license: %q{AGPL-3.0},
15
+ homepage: :blackwinter,
16
+ dependencies: %w[ruby-nuggets],
17
+
18
+ required_ruby_version: '>= 1.9.3'
19
+ }
20
+ }}
21
+ rescue LoadError => err
22
+ warn "Please install the `hen' gem. (#{err})"
23
+ end
data/lib/midos.rb ADDED
@@ -0,0 +1,88 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ ###############################################################################
5
+ # #
6
+ # midos -- A Ruby client for MIDOS databases #
7
+ # #
8
+ # Copyright (C) 2014 Jens Wille #
9
+ # #
10
+ # Authors: #
11
+ # Jens Wille <jens.wille@gmail.com> #
12
+ # #
13
+ # midos is free software; you can redistribute it and/or modify it under the #
14
+ # terms of the GNU Affero General Public License as published by the Free #
15
+ # Software Foundation; either version 3 of the License, or (at your option) #
16
+ # any later version. #
17
+ # #
18
+ # midos 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 Affero General Public License for #
21
+ # more details. #
22
+ # #
23
+ # You should have received a copy of the GNU Affero General Public License #
24
+ # along with midos. If not, see <http://www.gnu.org/licenses/>. #
25
+ # #
26
+ ###############################################################################
27
+ #++
28
+
29
+ module Midos
30
+
31
+ # Record separator
32
+ DEFAULT_RS = '&&&'
33
+
34
+ # Field separator
35
+ DEFAULT_FS = ':'
36
+
37
+ # Value separator
38
+ DEFAULT_VS = '|'
39
+
40
+ # Line break indicator
41
+ DEFAULT_NL = '^'
42
+
43
+ # Line ending
44
+ DEFAULT_LE = "\r\n"
45
+
46
+ # Default file encoding
47
+ DEFAULT_ENCODING = 'iso-8859-1'
48
+
49
+ class << self
50
+
51
+ def filter(source, target, source_options = {}, target_options = source_options)
52
+ writer, size = Writer.new(target_options.merge(:io => target)), 0
53
+
54
+ Reader.parse(source, source_options) { |*args|
55
+ writer << args and size += 1 if yield(*args)
56
+ }
57
+
58
+ size
59
+ end
60
+
61
+ def filter_file(source_file, target_file, source_options = {}, target_options = source_options, &block)
62
+ open_file(source_file, source_options) { |source|
63
+ open_file(target_file, target_options, 'w') { |target|
64
+ filter(source, target, source_options, target_options, &block)
65
+ }
66
+ }
67
+ end
68
+
69
+ def convert(*args)
70
+ filter(*args) { |*| true }
71
+ end
72
+
73
+ def convert_file(*args)
74
+ filter_file(*args) { |*| true }
75
+ end
76
+
77
+ def open_file(file, options = {}, mode = 'r', &block)
78
+ encoding = options[:encoding] ||= DEFAULT_ENCODING
79
+ File.open(file, mode, :encoding => encoding, &block)
80
+ end
81
+
82
+ end
83
+
84
+ end
85
+
86
+ require_relative 'midos/base'
87
+ require_relative 'midos/reader'
88
+ require_relative 'midos/writer'
data/lib/midos/base.rb ADDED
@@ -0,0 +1,80 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ ###############################################################################
5
+ # #
6
+ # midos -- A Ruby client for MIDOS databases #
7
+ # #
8
+ # Copyright (C) 2014 Jens Wille #
9
+ # #
10
+ # Authors: #
11
+ # Jens Wille <jens.wille@gmail.com> #
12
+ # #
13
+ # midos is free software; you can redistribute it and/or modify it under the #
14
+ # terms of the GNU Affero General Public License as published by the Free #
15
+ # Software Foundation; either version 3 of the License, or (at your option) #
16
+ # any later version. #
17
+ # #
18
+ # midos 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 Affero General Public License for #
21
+ # more details. #
22
+ # #
23
+ # You should have received a copy of the GNU Affero General Public License #
24
+ # along with midos. If not, see <http://www.gnu.org/licenses/>. #
25
+ # #
26
+ ###############################################################################
27
+ #++
28
+
29
+ module Midos
30
+
31
+ class Base
32
+
33
+ class << self
34
+
35
+ private
36
+
37
+ def file_method(method, mode, file, options = {}, *args, &block)
38
+ Midos.open_file(file, options, mode) { |io|
39
+ args.unshift(options.merge(:io => io))
40
+ method ? send(method, *args, &block) : block[new(*args)]
41
+ }
42
+ end
43
+
44
+ def extract_options!(args)
45
+ args.last.is_a?(Hash) ? args.pop : {}
46
+ end
47
+
48
+ end
49
+
50
+ def initialize(options = {}, &block)
51
+ self.key = options[:key]
52
+
53
+ self.rs = options[:rs] || DEFAULT_RS
54
+ self.fs = options[:fs] || DEFAULT_FS
55
+ self.vs = options[:vs] || DEFAULT_VS
56
+ self.nl = options[:nl] || DEFAULT_NL
57
+ self.le = options[:le] || DEFAULT_LE
58
+ self.io = options[:io] || self.class::DEFAULT_IO
59
+
60
+ @auto_id_block = options[:auto_id] || block
61
+ reset
62
+ end
63
+
64
+ attr_accessor :key, :rs, :fs, :nl, :le, :io, :auto_id
65
+
66
+ attr_reader :vs
67
+
68
+ def reset
69
+ @auto_id = @auto_id_block ? @auto_id_block.call : default_auto_id
70
+ end
71
+
72
+ private
73
+
74
+ def default_auto_id(n = 0)
75
+ lambda { n += 1 }
76
+ end
77
+
78
+ end
79
+
80
+ end
@@ -0,0 +1,116 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ ###############################################################################
5
+ # #
6
+ # midos -- A Ruby client for MIDOS databases #
7
+ # #
8
+ # Copyright (C) 2014 Jens Wille #
9
+ # #
10
+ # Authors: #
11
+ # Jens Wille <jens.wille@gmail.com> #
12
+ # #
13
+ # midos is free software; you can redistribute it and/or modify it under the #
14
+ # terms of the GNU Affero General Public License as published by the Free #
15
+ # Software Foundation; either version 3 of the License, or (at your option) #
16
+ # any later version. #
17
+ # #
18
+ # midos 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 Affero General Public License for #
21
+ # more details. #
22
+ # #
23
+ # You should have received a copy of the GNU Affero General Public License #
24
+ # along with midos. If not, see <http://www.gnu.org/licenses/>. #
25
+ # #
26
+ ###############################################################################
27
+ #++
28
+
29
+ module Midos
30
+
31
+ class Reader < Base
32
+
33
+ DEFAULT_IO = $stdin
34
+
35
+ class << self
36
+
37
+ def parse(*args, &block)
38
+ reader = new(extract_options!(args)).parse(*args, &block)
39
+ block ? reader : reader.records
40
+ end
41
+
42
+ def parse_file(*args, &block)
43
+ file_method(:parse, 'r', *args, &block)
44
+ end
45
+
46
+ end
47
+
48
+ attr_reader :records
49
+
50
+ def reset
51
+ super
52
+ @records = {}
53
+ end
54
+
55
+ def vs=(vs)
56
+ @vs = vs.is_a?(Regexp) ? vs : %r{\s*#{Regexp.escape(vs)}\s*}
57
+ end
58
+
59
+ def parse(io = io, &block)
60
+ unless block
61
+ records, block = @records, amend_block { |id, record|
62
+ records[id] = record
63
+ }
64
+ end
65
+
66
+ rs, fs, vs, nl, le, key, auto_id, id, record =
67
+ @rs, @fs, @vs, @nl, @le, @key, @auto_id, nil, {}
68
+
69
+ io.each { |line|
70
+ line = line.chomp(le)
71
+
72
+ if line == rs
73
+ block[key ? id : auto_id.call, record]
74
+ id, record = nil, {}
75
+ else
76
+ k, v = line.split(fs, 2)
77
+
78
+ if k && v
79
+ if k == key
80
+ id = v
81
+ else
82
+ v.gsub!(nl, "\n")
83
+ v = v.split(vs) if v.index(vs)
84
+ end
85
+
86
+ record[k] = v
87
+ end
88
+ end
89
+ }
90
+
91
+ self
92
+ end
93
+
94
+ private
95
+
96
+ def amend_block(&block)
97
+ return block unless $VERBOSE && k = @key
98
+
99
+ r, i = block.binding.eval('_ = records, io')
100
+
101
+ l = i.respond_to?(:lineno)
102
+ s = i.respond_to?(:path) ? i.path :
103
+ Object.instance_method(:inspect).bind(i).call
104
+
105
+ lambda { |id, *args|
106
+ if (r ||= block.binding.eval('records')).key?(id)
107
+ warn "Duplicate record in #{s}#{":#{i.lineno}" if l}: »#{k}:#{id}«"
108
+ end
109
+
110
+ block[id, *args]
111
+ }
112
+ end
113
+
114
+ end
115
+
116
+ end
@@ -0,0 +1,27 @@
1
+ module Midos
2
+
3
+ module Version
4
+
5
+ MAJOR = 0
6
+ MINOR = 0
7
+ TINY = 1
8
+
9
+ class << self
10
+
11
+ # Returns array representation.
12
+ def to_a
13
+ [MAJOR, MINOR, TINY]
14
+ end
15
+
16
+ # Short-cut for version string.
17
+ def to_s
18
+ to_a.join('.')
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+
25
+ VERSION = Version.to_s
26
+
27
+ end
@@ -0,0 +1,251 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ ###############################################################################
5
+ # #
6
+ # midos -- A Ruby client for MIDOS databases #
7
+ # #
8
+ # Copyright (C) 2014 Jens Wille #
9
+ # #
10
+ # Authors: #
11
+ # Jens Wille <jens.wille@gmail.com> #
12
+ # #
13
+ # midos is free software; you can redistribute it and/or modify it under the #
14
+ # terms of the GNU Affero General Public License as published by the Free #
15
+ # Software Foundation; either version 3 of the License, or (at your option) #
16
+ # any later version. #
17
+ # #
18
+ # midos 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 Affero General Public License for #
21
+ # more details. #
22
+ # #
23
+ # You should have received a copy of the GNU Affero General Public License #
24
+ # along with midos. If not, see <http://www.gnu.org/licenses/>. #
25
+ # #
26
+ ###############################################################################
27
+ #++
28
+
29
+ require 'nuggets/hash/idmap'
30
+
31
+ module Midos
32
+
33
+ class Writer < Base
34
+
35
+ DEFAULT_IO = $stdout
36
+
37
+ class << self
38
+
39
+ def write(*args, &block)
40
+ new(extract_options!(args), &block).write(*args)
41
+ end
42
+
43
+ def write_file(*args, &block)
44
+ file_method(:write, 'w', *args, &block)
45
+ end
46
+
47
+ def open(*args, &block)
48
+ file_method(nil, 'w', *args, &block)
49
+ end
50
+
51
+ end
52
+
53
+ def vs=(vs)
54
+ vs.is_a?(String) ? @vs = vs : raise(TypeError,
55
+ "wrong argument type #{vs.class} (expected String)")
56
+ end
57
+
58
+ def write(records, *args)
59
+ if records.is_a?(Hash)
60
+ records.each { |id, record| write_i(id, record, *args) }
61
+ else
62
+ records.each { |record| write_i(nil, record, *args) }
63
+ end
64
+
65
+ self
66
+ end
67
+
68
+ def put(record, *args)
69
+ if record.is_a?(Hash)
70
+ write_i(nil, record, *args)
71
+ else
72
+ write_i(*args.unshift(*record))
73
+ end
74
+
75
+ self
76
+ end
77
+
78
+ alias_method :<<, :put
79
+
80
+ private
81
+
82
+ def write_i(id, record, io = io)
83
+ return if record.empty?
84
+
85
+ if @key && !record.key?(@key)
86
+ record[@key] = id || @auto_id.call
87
+ end
88
+
89
+ record.each { |k, v|
90
+ if v
91
+ if k
92
+ v = v.is_a?(Array) ? v.join(@vs) : v.to_s
93
+ io << k << @fs << v.gsub("\n", @nl) << @le
94
+ else
95
+ Array(v).each { |w| io << w.to_s << @le }
96
+ end
97
+ end
98
+ }
99
+
100
+ io << @rs << @le << @le
101
+ end
102
+
103
+ class Thesaurus < self
104
+
105
+ PROLOGUE = {
106
+ :PAR => '1011111111110000000010001000000000000010',
107
+ :DAT => '00000000',
108
+ :DES => 'DE',
109
+ :TOP => 'TP~TP',
110
+ :KLA => 'CC~CC',
111
+ :OBR => 'BT~BT',
112
+ :UTR => 'NT~NT',
113
+ :SYN => 'UF~USE',
114
+ :FRU => 'PT~PT für',
115
+ :VER => 'RT~RT',
116
+ :SP1 => 'ENG~ENG für',
117
+ :SP2 => 'FRA~FRA für',
118
+ :SP3 => 'SPA~SPA für',
119
+ :SP4 => 'ITA~ITA für',
120
+ :SP5 => 'GRI~GRI für',
121
+ :SP6 => 'RUS~RUS für',
122
+ :SP7 => 'POL~POL für',
123
+ :SP8 => 'UNG~UNG für',
124
+ :SP9 => 'TSC~TSC für',
125
+ :SN1 => 'SN1',
126
+ :SN2 => 'SN2',
127
+ :SN3 => 'SN3',
128
+ :SN4 => 'SN4',
129
+ :SN5 => 'SN5',
130
+ :DA1 => 'DATE1',
131
+ :DA2 => 'DATE2',
132
+ :DA3 => 'DATE3',
133
+ :DA4 => 'DATE4',
134
+ :KLD => 'MIDOS Thesaurus',
135
+ :KOM => ' / ',
136
+ :KO1 => 'UF',
137
+ :KO2 => 'USE',
138
+ :TLE => ' 32000 Zeichen',
139
+ :PAW => '',
140
+ :ART => '00000',
141
+ :REL => ' 17 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 18 19 20 21 22 23 24 25'
142
+ }
143
+
144
+ EPILOGUE = {
145
+ :DE => '*****NICHTDESKRIPTORRELATIONEN*****'
146
+ }
147
+
148
+ RESOLVE_FROM = [:OBR, :UTR, :VER]
149
+
150
+ RESOLVE_TO = :DES
151
+
152
+ NAME = :KLD
153
+
154
+ class << self
155
+
156
+ def write(*args, &block)
157
+ new(extract_options!(args), &block).instruct! { |mth| mth.write(*args) }
158
+ end
159
+
160
+ def open(*args, &block)
161
+ super { |mth| mth.instruct!(&block) }
162
+ end
163
+
164
+ end
165
+
166
+ def initialize(options = {}, prologue = {}, epilogue = {}, &block)
167
+ super(options, &block)
168
+
169
+ prologue[self.class::NAME] ||= options[:name]
170
+
171
+ @prologue = self.class::PROLOGUE.merge(prologue)
172
+ @epilogue = self.class::EPILOGUE.merge(epilogue)
173
+ end
174
+
175
+ attr_reader :prologue, :epilogue
176
+
177
+ def instruct!(*args)
178
+ put(prologue, *args)
179
+ yield self
180
+ put(epilogue, *args)
181
+ end
182
+
183
+ private
184
+
185
+ def merge_records(hash, records, *args)
186
+ args = [hash, records, *resolve_from_to(*args)]
187
+
188
+ records.each { |id, record|
189
+ new_record = hash[id] = {}
190
+ record.each { |key, value| new_record[key] = resolve(key, value, *args) }
191
+ }
192
+ end
193
+
194
+ def resolve_from_to(from = nil, to = prologue[RESOLVE_TO])
195
+ if from.nil? || from == true
196
+ from = prologue.values_at(*RESOLVE_FROM).map { |v| v.split('~').first }
197
+ end
198
+
199
+ [from, to]
200
+ end
201
+
202
+ def resolve(key, value, hash, records, from = nil, to = nil)
203
+ from && from.include?(key) ? value.map { |id| records[id][to] } : value
204
+ end
205
+
206
+ end
207
+
208
+ class ThesaurusX < Thesaurus
209
+
210
+ PROLOGUE = {
211
+ 'MTX-PARAMETER' => '',
212
+ :BEZ => 'MIDOS Thesaurus',
213
+ :KOM => ' / ',
214
+ :TXL => 0,
215
+ :REL => '',
216
+ nil => %w[
217
+ TT1|Topterm|TT1||||||
218
+ BT1|Oberbegriff|BT1||||||
219
+ NT1|Unterbegriff|NT1||||||
220
+ RT1|Verwandter\ Begriff|RT1||||||
221
+ SY1|Synonym1|SY1|SY1FOR|||||
222
+ ]
223
+ }
224
+
225
+ EPILOGUE = {}
226
+
227
+ NAME = :BEZ
228
+
229
+ private
230
+
231
+ def merge_records(hash, *)
232
+ idmap = hash[:__list__] = Hash.idmap
233
+
234
+ super
235
+
236
+ idmap.replace(nil => idmap.map { |key, id| "#{key}|DE|#{id}" })
237
+ end
238
+
239
+ def resolve_from_to(*)
240
+ # nothing to do
241
+ end
242
+
243
+ def resolve(key, value, hash, *)
244
+ value.map { |id| hash[:__list__][id] }
245
+ end
246
+
247
+ end
248
+
249
+ end
250
+
251
+ end