midos 0.0.1

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.
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