lingo 1.8.4.2 → 1.8.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +413 -325
  3. data/README +380 -131
  4. data/Rakefile +19 -21
  5. data/de/lingo-abk.txt +15 -17
  6. data/de/lingo-dic.txt +20210 -20659
  7. data/de/lingo-mul.txt +5 -13
  8. data/de/lingo-syn.txt +5 -8
  9. data/de/test_dic.txt +2 -0
  10. data/de/test_gen.txt +8 -0
  11. data/de/{test_mul2.txt → test_mu2.txt} +0 -0
  12. data/de/{test_singleword.txt → test_sgw.txt} +0 -0
  13. data/de/user-dic.txt +5 -7
  14. data/de.lang +64 -49
  15. data/en/lingo-dic.txt +6398 -6404
  16. data/en/lingo-irr.txt +2 -3
  17. data/en/lingo-mul.txt +6 -7
  18. data/en/lingo-wdn.txt +881 -1762
  19. data/en/user-dic.txt +2 -5
  20. data/en.lang +39 -39
  21. data/lib/lingo/app.rb +10 -6
  22. data/lib/lingo/attendee/abbreviator.rb +1 -0
  23. data/lib/lingo/attendee/decomposer.rb +2 -1
  24. data/lib/lingo/attendee/multi_worder.rb +5 -6
  25. data/lib/lingo/attendee/stemmer.rb +1 -1
  26. data/lib/lingo/attendee/synonymer.rb +4 -2
  27. data/lib/lingo/attendee/text_reader.rb +77 -57
  28. data/lib/lingo/attendee/text_writer.rb +1 -1
  29. data/lib/lingo/attendee/tokenizer.rb +101 -50
  30. data/lib/lingo/attendee/variator.rb +2 -1
  31. data/lib/lingo/attendee/vector_filter.rb +28 -6
  32. data/lib/lingo/attendee/word_searcher.rb +2 -1
  33. data/lib/lingo/attendee.rb +8 -4
  34. data/lib/lingo/call.rb +7 -3
  35. data/lib/lingo/cli.rb +8 -16
  36. data/lib/lingo/config.rb +11 -6
  37. data/lib/lingo/ctl.rb +54 -3
  38. data/lib/lingo/database/crypter.rb +8 -14
  39. data/lib/lingo/database/hash_store.rb +1 -1
  40. data/lib/lingo/database/{show_progress.rb → progress.rb} +7 -8
  41. data/lib/lingo/database/source/key_value.rb +6 -5
  42. data/lib/lingo/database/source/multi_key.rb +5 -2
  43. data/lib/lingo/database/source/multi_value.rb +6 -4
  44. data/lib/lingo/database/source/single_word.rb +2 -3
  45. data/lib/lingo/database/source/word_class.rb +24 -5
  46. data/lib/lingo/database/source.rb +5 -3
  47. data/lib/lingo/database.rb +102 -41
  48. data/lib/lingo/error.rb +24 -2
  49. data/lib/lingo/language/dictionary.rb +26 -54
  50. data/lib/lingo/language/grammar.rb +19 -23
  51. data/lib/lingo/language/lexical.rb +5 -1
  52. data/lib/lingo/language/lexical_hash.rb +7 -12
  53. data/lib/lingo/language/token.rb +10 -1
  54. data/lib/lingo/language/word.rb +35 -23
  55. data/lib/lingo/language/word_form.rb +5 -4
  56. data/lib/lingo/{show_progress.rb → progress.rb} +43 -30
  57. data/lib/lingo/srv/lingosrv.cfg +1 -1
  58. data/lib/lingo/srv/public/.gitkeep +0 -0
  59. data/lib/lingo/srv.rb +11 -6
  60. data/lib/lingo/version.rb +2 -2
  61. data/lib/lingo/web/lingoweb.cfg +1 -1
  62. data/lib/lingo/web/views/index.erb +4 -4
  63. data/lib/lingo/web.rb +4 -6
  64. data/lib/lingo.rb +4 -12
  65. data/lingo.cfg +1 -1
  66. data/lir.cfg +1 -1
  67. data/ru/lingo-dic.txt +33473 -2113
  68. data/ru/lingo-mul.txt +8430 -1913
  69. data/ru/lingo-syn.txt +1634 -0
  70. data/ru/user-dic.txt +6 -0
  71. data/ru.lang +49 -47
  72. data/spec/spec_helper.rb +4 -0
  73. data/test/attendee/ts_decomposer.rb +2 -2
  74. data/test/attendee/ts_synonymer.rb +3 -3
  75. data/test/attendee/ts_tokenizer.rb +215 -2
  76. data/test/attendee/ts_variator.rb +2 -2
  77. data/test/attendee/ts_word_searcher.rb +10 -6
  78. data/test/ref/artikel.seq +2 -2
  79. data/test/ref/artikel.vec +5 -5
  80. data/test/ref/artikel.ven +11 -11
  81. data/test/ref/artikel.ver +11 -11
  82. data/test/ref/lir.seq +13 -13
  83. data/test/ref/lir.vec +31 -31
  84. data/test/test_helper.rb +19 -5
  85. data/test/ts_database.rb +206 -77
  86. data/test/ts_language.rb +86 -26
  87. metadata +93 -49
  88. data/.rspec +0 -1
  89. data/de/test_syn2.txt +0 -1
data/test/ts_database.rb CHANGED
@@ -2,16 +2,6 @@
2
2
 
3
3
  require_relative 'test_helper'
4
4
 
5
- class Lingo::Database
6
-
7
- alias_method :original_convert, :convert
8
-
9
- def convert(verbose = false)
10
- original_convert(verbose)
11
- end
12
-
13
- end
14
-
15
5
  class TestDatabase < LingoTestCase
16
6
 
17
7
  def setup
@@ -29,6 +19,28 @@ ganz großer und blöder mist
29
19
  ganz großer und blöder schwach sinn
30
20
  EOT
31
21
 
22
+ @singleword_inflect = <<-EOT
23
+ Wort1
24
+ Wort2
25
+ juristisch person
26
+ natürliche personen
27
+ natürlichen quatsches
28
+ klug abel
29
+ lang essay
30
+ große kiefer
31
+ warm abendluft
32
+ klar abendluft
33
+ gut abitur
34
+ gut abitur schaffen
35
+ ein gut abitur
36
+ schmal rund zylinder
37
+ der schmal zylinder
38
+ wort mist
39
+ alt bibliothekskatalog
40
+ neu bibliothekskatalög
41
+ neu alttitelkatalog
42
+ EOT
43
+
32
44
  @keyvalue = <<-EOT
33
45
  Wort1*Projektion1
34
46
  Wort2*Projektion2
@@ -55,14 +67,14 @@ Wort2=
55
67
  compare({
56
68
  'txt-format' => 'SingleWord'
57
69
  }, @singleword, {
58
- 'wort1' => '#s',
59
- 'wort2' => '#s',
60
- 'juristische personen' => '#s',
61
- 'höher schneller weiter' => '#s',
62
- 'höher schneller weiter größer' => '#s',
63
- 'ganz großer und blöder quatsch' => '#s',
64
- 'ganz großer und blöder mist' => '#s',
65
- 'ganz großer und blöder schwach sinn' => '#s'
70
+ 'wort1' => 'wort1#s',
71
+ 'wort2' => 'wort2#s',
72
+ 'juristische personen' => 'juristische personen#s',
73
+ 'höher schneller weiter' => 'höher schneller weiter#s',
74
+ 'höher schneller weiter größer' => 'höher schneller weiter größer#s',
75
+ 'ganz großer und blöder quatsch' => 'ganz großer und blöder quatsch#s',
76
+ 'ganz großer und blöder mist' => 'ganz großer und blöder mist#s',
77
+ 'ganz großer und blöder schwach sinn' => 'ganz großer und blöder schwach sinn#s'
66
78
  })
67
79
  end
68
80
 
@@ -71,14 +83,14 @@ Wort2=
71
83
  'txt-format' => 'SingleWord',
72
84
  'def-wc' => '*'
73
85
  }, @singleword, {
74
- 'wort1' => '#*',
75
- 'wort2' => '#*',
76
- 'juristische personen' => '#*',
77
- 'höher schneller weiter' => '#*',
78
- 'höher schneller weiter größer' => '#*',
79
- 'ganz großer und blöder quatsch' => '#*',
80
- 'ganz großer und blöder mist' => '#*',
81
- 'ganz großer und blöder schwach sinn' => '#*'
86
+ 'wort1' => 'wort1#*',
87
+ 'wort2' => 'wort2#*',
88
+ 'juristische personen' => 'juristische personen#*',
89
+ 'höher schneller weiter' => 'höher schneller weiter#*',
90
+ 'höher schneller weiter größer' => 'höher schneller weiter größer#*',
91
+ 'ganz großer und blöder quatsch' => 'ganz großer und blöder quatsch#*',
92
+ 'ganz großer und blöder mist' => 'ganz großer und blöder mist#*',
93
+ 'ganz großer und blöder schwach sinn' => 'ganz großer und blöder schwach sinn#*'
82
94
  })
83
95
  end
84
96
 
@@ -87,14 +99,14 @@ Wort2=
87
99
  'txt-format' => 'SingleWord',
88
100
  'def-mul-wc' => 'm'
89
101
  }, @singleword, {
90
- 'wort1' => '#s',
91
- 'wort2' => '#s',
92
- 'juristische personen' => '#m',
93
- 'höher schneller weiter' => '#m',
94
- 'höher schneller weiter größer' => '#m',
95
- 'ganz großer und blöder quatsch' => '#m',
96
- 'ganz großer und blöder mist' => '#m',
97
- 'ganz großer und blöder schwach sinn' => '#m'
102
+ 'wort1' => 'wort1#s',
103
+ 'wort2' => 'wort2#s',
104
+ 'juristische personen' => 'juristische personen#m',
105
+ 'höher schneller weiter' => 'höher schneller weiter#m',
106
+ 'höher schneller weiter größer' => 'höher schneller weiter größer#m',
107
+ 'ganz großer und blöder quatsch' => 'ganz großer und blöder quatsch#m',
108
+ 'ganz großer und blöder mist' => 'ganz großer und blöder mist#m',
109
+ 'ganz großer und blöder schwach sinn' => 'ganz großer und blöder schwach sinn#m'
98
110
  })
99
111
  end
100
112
 
@@ -107,11 +119,11 @@ Wort2=
107
119
  'separator' => '='
108
120
  )
109
121
  }, @singleword, {
110
- 'wort1' => '#s',
111
- 'wort2' => '#s',
122
+ 'wort1' => 'wort1#s',
123
+ 'wort2' => 'wort2#s',
112
124
  'ganz groß und blöd mist' => 'ganz großer und blöder mist#s',
113
125
  'juristisch person' => 'juristische personen#s',
114
- 'hoch schnell weit' => '*4|höher schneller weiter#s',
126
+ 'hoch schnell weit' => 'höher schneller weiter#s|*4',
115
127
  'ganz groß und blöd quatsch' => 'ganz großer und blöder quatsch#s',
116
128
  'hoch schnell weit groß' => 'höher schneller weiter größer#s',
117
129
  'ganz groß und blöd schwach sinn' => 'ganz großer und blöder schwach sinn#s',
@@ -119,33 +131,125 @@ Wort2=
119
131
  })
120
132
  end
121
133
 
134
+ def test_singleword_inflect
135
+ compare({
136
+ 'txt-format' => 'SingleWord',
137
+ 'use-lex' => set_config('lex',
138
+ 'name' => 'de/lingo-dic.txt',
139
+ 'txt-format' => 'WordClass',
140
+ 'separator' => '='
141
+ ),
142
+ 'inflect' => true
143
+ }, @singleword_inflect, {
144
+ 'wort1' => 'wort1#s',
145
+ 'wort2' => 'wort2#s',
146
+ 'juristisch person' => 'juristische person#s',
147
+ 'natürlich person' => 'natürliche personen#s',
148
+ 'natürlich quatsch' => 'natürlichen quatsches#s',
149
+ 'lang essay' => 'langer essay#s',
150
+ 'groß kiefer' => 'große kiefer#s',
151
+ 'klug abel' => 'kluger abel#s',
152
+ 'warm abendluft' => 'warme abendluft#s',
153
+ 'klar abendluft' => 'klare abendluft#s',
154
+ 'gut abitur' => 'gutes abitur#s',
155
+ 'gut abitur schaff' => 'gutes abitur schaffen#s',
156
+ 'ein gut abitur' => 'ein gut abitur#s',
157
+ 'schmal rund zylinder' => 'schmaler runder zylinder#s',
158
+ 'der schmal zylinder' => 'der schmal zylinder#s',
159
+ 'wort mist' => 'wort mist#s',
160
+ 'alt bibliothekskatalog' => 'alter bibliothekskatalog#s',
161
+ 'neu bibliothekskatalög' => 'neu bibliothekskatalög#s',
162
+ 'neu alttitelkatalog' => 'neuer alttitelkatalog#s'
163
+ })
164
+ end
165
+
166
+ def test_singleword_inflect_s
167
+ compare({
168
+ 'txt-format' => 'SingleWord',
169
+ 'use-lex' => set_config('lex',
170
+ 'name' => 'de/lingo-dic.txt',
171
+ 'txt-format' => 'WordClass',
172
+ 'separator' => '='
173
+ ),
174
+ 'inflect' => 's'
175
+ }, @singleword_inflect, {
176
+ 'wort1' => 'wort1#s',
177
+ 'wort2' => 'wort2#s',
178
+ 'juristisch person' => 'juristische person#s',
179
+ 'natürlich person' => 'natürliche personen#s',
180
+ 'natürlich quatsch' => 'natürlichen quatsches#s',
181
+ 'lang essay' => 'langer essay#s',
182
+ 'groß kiefer' => 'große kiefer#s',
183
+ 'klug abel' => 'klug abel#s',
184
+ 'warm abendluft' => 'warme abendluft#s',
185
+ 'klar abendluft' => 'klare abendluft#s',
186
+ 'gut abitur' => 'gutes abitur#s',
187
+ 'gut abitur schaff' => 'gutes abitur schaffen#s',
188
+ 'ein gut abitur' => 'ein gut abitur#s',
189
+ 'schmal rund zylinder' => 'schmaler runder zylinder#s',
190
+ 'der schmal zylinder' => 'der schmal zylinder#s',
191
+ 'wort mist' => 'wort mist#s',
192
+ 'alt bibliothekskatalog' => 'alter bibliothekskatalog#s',
193
+ 'neu bibliothekskatalög' => 'neu bibliothekskatalög#s',
194
+ 'neu alttitelkatalog' => 'neuer alttitelkatalog#s'
195
+ })
196
+ end
197
+
198
+ def test_singleword_inflect_e
199
+ compare({
200
+ 'txt-format' => 'SingleWord',
201
+ 'use-lex' => set_config('lex',
202
+ 'name' => 'de/lingo-dic.txt',
203
+ 'txt-format' => 'WordClass',
204
+ 'separator' => '='
205
+ ),
206
+ 'inflect' => 'e'
207
+ }, @singleword_inflect, {
208
+ 'wort1' => 'wort1#s',
209
+ 'wort2' => 'wort2#s',
210
+ 'juristisch person' => 'juristisch person#s',
211
+ 'natürlich person' => 'natürliche personen#s',
212
+ 'natürlich quatsch' => 'natürlichen quatsches#s',
213
+ 'lang essay' => 'lang essay#s',
214
+ 'klug abel' => 'kluger abel#s',
215
+ 'groß kiefer' => 'große kiefer#s',
216
+ 'warm abendluft' => 'warm abendluft#s',
217
+ 'klar abendluft' => 'klar abendluft#s',
218
+ 'gut abitur' => 'gut abitur#s',
219
+ 'gut abitur schaff' => 'gut abitur schaffen#s',
220
+ 'ein gut abitur' => 'ein gut abitur#s',
221
+ 'schmal rund zylinder' => 'schmal rund zylinder#s',
222
+ 'der schmal zylinder' => 'der schmal zylinder#s',
223
+ 'wort mist' => 'wort mist#s',
224
+ 'alt bibliothekskatalog' => 'alt bibliothekskatalog#s',
225
+ 'neu bibliothekskatalög' => 'neu bibliothekskatalög#s',
226
+ 'neu alttitelkatalog' => 'neu alttitelkatalog#s'
227
+ })
228
+ end
229
+
122
230
  def test_singleword_crypt
123
- config = {
231
+ compare({
124
232
  'txt-format' => 'SingleWord',
125
233
  'crypt' => true
126
- }
234
+ }, @singleword) { |db| hash = db.to_h; {
235
+ 'wort1' => 'wort1#s',
236
+ 'wort2' => 'wort2#s',
237
+ 'juristische personen' => 'juristische personen#s',
238
+ 'höher schneller weiter' => 'höher schneller weiter#s',
239
+ 'höher schneller weiter größer' => 'höher schneller weiter größer#s',
240
+ 'ganz großer und blöder quatsch' => 'ganz großer und blöder quatsch#s',
241
+ 'ganz großer und blöder mist' => 'ganz großer und blöder mist#s',
242
+ 'ganz großer und blöder schwach sinn' => 'ganz großer und blöder schwach sinn#s'
243
+ }.each { |key, val|
244
+ assert_nil(hash[key])
245
+ assert_equal([val], db[key])
127
246
 
128
- compare(config, @singleword, {
129
- 'd8ac4360a5f707d518212e27dcba9dd42d980f96' => '5116',
130
- '81463f9c7e0ad40e329e83d3358232851d50ed9a' => '4d16',
131
- '8da4a0c30c912543be2d88da64c0192e577efa9d' => '1107',
132
- '2c24b4707e77c74abfb12748317693dc1e43c215' => '5700',
133
- '810ff7a76f39febcb1cf67993d4fb29819ce40a6' => '5116',
134
- 'a28b4ca84ac08aeef4e420445f94f632ad010a30' => '1207',
135
- '1496f4febbc647f3ac74b0af11dadbd6322f6732' => '4d1d',
136
- 'b7501a62cb083be6730a7a179a4ab346d23efe53' => '4b10'
137
- })
247
+ assert_nil(db[digest = Lingo::Database::Crypter.digest(key)])
248
+ assert_not_equal(key, digest)
138
249
 
139
- compare(config, @singleword) { |db| {
140
- 'wort1' => '#s',
141
- 'wort2' => '#s',
142
- 'juristische personen' => '#s',
143
- 'höher schneller weiter' => '#s',
144
- 'höher schneller weiter größer' => '#s',
145
- 'ganz großer und blöder quatsch' => '#s',
146
- 'ganz großer und blöder mist' => '#s',
147
- 'ganz großer und blöder schwach sinn' => '#s'
148
- }.each { |key, val| assert_equal([val], db[key]) } }
250
+ assert_instance_of(String, encrypted = hash[digest])
251
+ assert_not_equal(val, encrypted)
252
+ } }
149
253
  end
150
254
 
151
255
  def test_keyvalue
@@ -198,10 +302,39 @@ Wort2=
198
302
  Wort1=Projektion4 #e
199
303
  Wort1=#s
200
304
  Wort2=
305
+ Wort4.illegal
306
+ Wort4=still illegal
307
+ Wort4=still illegal#s!
308
+ Wort4=now we're talking#s+
309
+ }, {
310
+ 'wort1' => 'projektion1#h#|projektion4#e#',
311
+ 'wort2' => 'projektion2#i#',
312
+ 'wort3' => 'projektion3#e#',
313
+ 'wort4' => "now we're talking#s+#"
314
+ })
315
+ end
316
+
317
+ def test_wordclass_gender
318
+ compare({
319
+ 'txt-format' => 'WordClass'
320
+ }, %q{
321
+ substantiv,substantiv #a substantiv #s.n
322
+ mehr,mehr #w mehr #s.n mehren #v
323
+ wort,wort #s.n
324
+ gruppe,gruppe #s.f
325
+ modul,modul #s.m|n
326
+ nocken,nock #s.f|m|n nocke #s.f nocken #s.m
327
+ albern,albern #a|v
328
+ fortuna,fortuna #e|s.f
201
329
  }, {
202
- 'wort1' => 'projektion1#h|projektion4#e',
203
- 'wort2' => 'projektion2#i',
204
- 'wort3' => 'projektion3#e'
330
+ 'substantiv' => 'substantiv#a#|substantiv#s#n',
331
+ 'mehr' => 'mehr#w#|mehr#s#n|mehren#v#',
332
+ 'wort' => 'wort#s#n',
333
+ 'gruppe' => 'gruppe#s#f',
334
+ 'modul' => 'modul#s#m|modul#s#n',
335
+ 'nocken' => 'nock#s#f|nock#s#m|nock#s#n|nocke#s#f|nocken#s#m',
336
+ 'albern' => 'albern#a#|albern#v#',
337
+ 'fortuna' => 'fortuna#e#f|fortuna#s#f'
205
338
  })
206
339
  end
207
340
 
@@ -215,21 +348,17 @@ Wort2=
215
348
  Rasen;Gras;Grüne Fläche
216
349
  Rasen;Rennen;Wettrennen
217
350
  }, {
218
- '^0' => 'hasen|nasen|rasen|vasen',
219
- '^1' => 'edelmetall|gold|mehrwert',
220
- '^2' => 'gras|grüne fläche|rasen',
221
- '^3' => 'rasen|rennen|wettrennen',
222
- 'hasen' => '^0',
223
- 'nasen' => '^0',
224
- 'rasen' => '^0|^2|^3',
225
- 'vasen' => '^0',
226
- 'edelmetall' => '^1',
227
- 'gold' => '^1',
228
- 'mehrwert' => '^1',
229
- 'gras' => '^2',
230
- 'grüne fläche' => '^2',
231
- 'wettrennen' => '^3',
232
- 'rennen' => '^3'
351
+ 'hasen' => 'hasen|nasen|vasen|rasen',
352
+ 'nasen' => 'hasen|nasen|vasen|rasen',
353
+ 'vasen' => 'hasen|nasen|vasen|rasen',
354
+ 'rasen' => 'hasen|nasen|vasen|rasen|gras|grüne fläche|rennen|wettrennen',
355
+ 'gold' => 'gold|edelmetall|mehrwert',
356
+ 'edelmetall' => 'gold|edelmetall|mehrwert',
357
+ 'mehrwert' => 'gold|edelmetall|mehrwert',
358
+ 'gras' => 'rasen|gras|grüne fläche',
359
+ 'grüne fläche' => 'rasen|gras|grüne fläche',
360
+ 'rennen' => 'rasen|rennen|wettrennen',
361
+ 'wettrennen' => 'rasen|rennen|wettrennen'
233
362
  })
234
363
  end
235
364
 
data/test/ts_language.rb CHANGED
@@ -27,9 +27,9 @@ class TestLexicalHash < LingoTestCase
27
27
 
28
28
  def test_cache
29
29
  lh('sys-dic') { |ds|
30
- assert_equal([lx('regen|s'), lx('regen|v'), lx('rege|a')], ds['regen'])
31
- assert_equal([lx('regen|s'), lx('regen|v'), lx('rege|a')], ds['regen'])
32
- assert_equal([lx('regen|s'), lx('regen|v'), lx('rege|a')], ds['regen'])
30
+ assert_equal([lx('regen|s|m'), lx('regen|s|n'), lx('regen|v'), lx('rege|a')], ds['regen'])
31
+ assert_equal([lx('regen|s|m'), lx('regen|s|n'), lx('regen|v'), lx('rege|a')], ds['regen'])
32
+ assert_equal([lx('regen|s|m'), lx('regen|s|n'), lx('regen|v'), lx('rege|a')], ds['regen'])
33
33
  }
34
34
  end
35
35
 
@@ -57,7 +57,7 @@ class TestLexicalHash < LingoTestCase
57
57
  def test_keyvalue
58
58
  lh('sys-mul') { |ds|
59
59
  assert_equal([lx('abelscher ring ohne nullteiler|m')], ds['abelscher ring ohne nullteiler'])
60
- assert_equal(['*4'], ds['abelscher ring ohne'])
60
+ assert_equal([4], ds['abelscher ring ohne'])
61
61
  assert_equal([lx('alleinreisende frau|m')], ds['alleinreisend frau'])
62
62
  assert_equal([lx('abschaltbarer leistungshalbleiter|m')], ds['abschaltbar leistungshalbleiter'])
63
63
  assert_equal(nil, ds['abschaltbarer leistungshalbleiter'])
@@ -66,12 +66,25 @@ class TestLexicalHash < LingoTestCase
66
66
 
67
67
  def test_wordclass
68
68
  lh('sys-dic') { |ds|
69
- assert_equal([lx('a-dur|s')], ds['a-dur'])
70
- assert_equal([lx('aalen|v'), lx('aalen|e')], ds['aalen'])
69
+ assert_equal([lx('a-dur|s|m'), lx('a-dur|s|n')], ds['a-dur'])
70
+ assert_equal([lx('aalen|e'), lx('aalen|v')], ds['aalen'])
71
71
  assert_equal([lx('abarbeitend|a')], ds['abarbeitend'])
72
72
  }
73
73
  end
74
74
 
75
+ def test_wordclass_gender
76
+ lh('tst-gen') { |ds|
77
+ assert_equal([lx('substantiv|a'), lx('substantiv|s|n')], ds['substantiv'])
78
+ assert_equal([lx('mehr|w'), lx('mehr|s|n'), lx('mehren|v')], ds['mehr'])
79
+ assert_equal([lx('wort|s|n')], ds['wort'])
80
+ assert_equal([lx('gruppe|s|f')], ds['gruppe'])
81
+ assert_equal([lx('modul|s|m'), lx('modul|s|n')], ds['modul'])
82
+ assert_equal([lx('nock|s|f'), lx('nock|s|m'), lx('nock|s|n'), lx('nocke|s|f'), lx('nocken|s|m')], ds['nocken'])
83
+ assert_equal([lx('albern|a'), lx('albern|v')], ds['albern'])
84
+ assert_equal([lx('fortuna|e|f'), lx('fortuna|s|f')], ds['fortuna'])
85
+ }
86
+ end
87
+
75
88
  def test_case
76
89
  lh('sys-dic') { |ds|
77
90
  assert_equal([lx('abänderung|s')], ds['abänderung'])
@@ -83,7 +96,7 @@ class TestLexicalHash < LingoTestCase
83
96
  def test_multivalue
84
97
  lh('sys-syn') { |ds|
85
98
  assert_equal([lx('abbau <chemie>|y'), lx('chemische abbaureaktion|y'), lx('chemischer abbau|y'), lx('photochemischer abbau|y')], ds['abbaureaktion'])
86
- assert_equal([lx('dependenz|y'), lx('unselbstständigkeit|y'), lx('unselbständigkeit|y')], ds['abhängigkeit'])
99
+ assert_equal([lx('dependenz|y'), lx('unselbständigkeit|y'), lx('unselbstständigkeit|y')], ds['abhängigkeit'])
87
100
  }
88
101
  end
89
102
 
@@ -136,7 +149,7 @@ class TestDictionary < LingoTestCase
136
149
  # nur in zweiter Quelle vorhanden
137
150
  assert_equal([lx('super indexierungssystem|m')], dic.select('lex-lingo'))
138
151
  # in beiden Quellen vorhanden
139
- assert_equal([lx('a-dur|s')], dic.select('a-dur'))
152
+ assert_equal([lx('a-dur|s|m'), lx('a-dur|s|n')], dic.select('a-dur'))
140
153
  }
141
154
  end
142
155
 
@@ -162,8 +175,8 @@ class TestDictionary < LingoTestCase
162
175
  # nur in zweiter Quelle vorhanden
163
176
  assert_equal([lx('super indexierungssystem|m')], dic.select('lex-lingo'))
164
177
  # in beiden Quellen vorhanden
165
- assert_equal([lx('a-dur|s'), lx('b-dur|s')], dic.select('a-dur'))
166
- assert_equal([lx('aas|s')], dic.select('aas'))
178
+ assert_equal([lx('a-dur|s|m'), lx('a-dur|s|n'), lx('b-dur|s')], dic.select('a-dur'))
179
+ assert_equal([lx('aas|s|n'), lx('aas|s')], dic.select('aas'))
167
180
  }
168
181
  end
169
182
 
@@ -175,24 +188,26 @@ class TestDictionary < LingoTestCase
175
188
  assert_equal([lx('knaller|s')], dic.select('knaller'))
176
189
  # nur in zweiter Quelle vorhanden
177
190
  assert_equal([lx('super indexierungssystem|m')], dic.select('lex-lingo'))
191
+ assert_equal([lx('wirkungsort|s'), lx('wirkung|s+'), lx('ort|s+')], dic.select('wirkungsort'))
192
+ assert_equal([lx('zettelkatalog|k'), lx('zettel|s+'), lx('katalog|s+')], dic.select('zettelkatalog'))
178
193
  # in beiden Quellen vorhanden
179
- assert_equal([lx('a-dur|s'), lx('b-dur|s')], dic.select('a-dur'))
180
- assert_equal([lx('aas|s')], dic.select('aas'))
194
+ assert_equal([lx('a-dur|s|m'), lx('a-dur|s|n'), lx('b-dur|s')], dic.select('a-dur'))
195
+ assert_equal([lx('aas|s|n'), lx('aas|s')], dic.select('aas'))
181
196
  }
182
197
  end
183
198
 
184
199
  def test_suffix_lexicals
185
200
  ld('source' => %w[sys-dic]) { |dic|
186
- assert_equal([lx('mau|s'), lx('mauer|s')], dic.suffix_lexicals('mauern'))
187
- assert_equal([lx('hasen|s'), lx('hasen|v'), lx('hasen|e')], dic.suffix_lexicals('hasens'))
188
- assert_equal([lx('schönst|s'), lx('schön|a'), lx('schönst|a')], dic.suffix_lexicals('schönster'))
189
- assert_equal([lx('segnen|v'), lx('segneen|v')], dic.suffix_lexicals('segnet'))
201
+ assert_equal([lx('mau|s'), lx('mauer|s')], ax(dic, 'mauern'))
202
+ assert_equal([lx('hasen|s'), lx('hasen|v'), lx('hasen|e')], ax(dic, 'hasens'))
203
+ assert_equal([lx('schönst|s'), lx('schön|a'), lx('schönst|a')], ax(dic, 'schönster'))
204
+ assert_equal([lx('segnen|v'), lx('segneen|v')], ax(dic, 'segnet'))
190
205
  }
191
206
  end
192
207
 
193
208
  def test_infix_lexicals
194
209
  ld('source' => %w[sys-dic]) { |dic|
195
- assert_equal( [lx('information|s'), lx('information|v'), lx('information|e')], dic.suffix_lexicals('informations'))
210
+ assert_equal( [lx('information|f'), lx('informationsen|f')], ax(dic, 'informations', :infix))
196
211
  }
197
212
  end
198
213
 
@@ -207,7 +222,7 @@ class TestDictionary < LingoTestCase
207
222
 
208
223
  def test_select_with_infix
209
224
  ld('source' => %w[sys-dic]) { |dic|
210
- assert_equal( [lx('information|s'), lx('information|v'), lx('information|e')], dic.suffix_lexicals('informations'))
225
+ assert_equal( [lx('information|f'), lx('informationsen|f')], ax(dic, 'informations', :infix))
211
226
  }
212
227
  end
213
228
 
@@ -223,6 +238,10 @@ class TestDictionary < LingoTestCase
223
238
  Lingo::Language::Dictionary.open(cfg, @lingo, &block)
224
239
  end
225
240
 
241
+ def ax(dic, *args)
242
+ [].tap { |x| dic.each_affix(*args) { |*a| x << Lingo::Language::Lexical.new(*a) } }
243
+ end
244
+
226
245
  end
227
246
 
228
247
  class TestGrammar < LingoTestCase
@@ -260,7 +279,7 @@ class TestGrammar < LingoTestCase
260
279
  )
261
280
 
262
281
  assert_equal(
263
- wd('cd-rom-technologie|KOM', 'cd-rom-technologie|k', 'cd-rom|s+', 'technologie|s+'),
282
+ wd('cd-rom-technologie|KOM', 'cd-rom-technologie|k', 'cd-rom|s+|f', 'cd-rom|s+|m', 'technologie|s+|f'),
264
283
  gra.find_compound('cd-rom-technologie')
265
284
  )
266
285
 
@@ -275,7 +294,7 @@ class TestGrammar < LingoTestCase
275
294
  )
276
295
 
277
296
  assert_equal(
278
- wd('benutzerforschung|KOM', 'benutzerforschung|k', 'erforschung|s+', 'benutzen|v+'),
297
+ wd('benutzerforschung|KOM', 'benutzerforschung|k', 'benutzen|v+', 'erforschung|s+'),
279
298
  gra.find_compound('benutzerforschung')
280
299
  )
281
300
 
@@ -284,6 +303,21 @@ class TestGrammar < LingoTestCase
284
303
  gra.find_compound('clustersuche')
285
304
  )
286
305
 
306
+ assert_equal(
307
+ wd('titelkatalogstitel|KOM', 'titelkatalogstitel|k', 'titel|s+', 'katalog|s+', 'titel|s+'),
308
+ gra.find_compound('titelkatalogstitel')
309
+ )
310
+
311
+ assert_equal(
312
+ wd('titelkatalogstiteltitel|KOM', 'titelkatalogstiteltitel|k', 'titel|s+', 'katalog|s+', 'titel|s+', 'titel|s+'),
313
+ gra.find_compound('titelkatalogstiteltitel')
314
+ )
315
+
316
+ assert_equal(
317
+ wd('titelbestandsbestände|KOM', 'titelbestandsbestand|k', 'titel|s+', 'bestand|s+', 'bestand|s+', 'bestehen|v+'),
318
+ gra.find_compound('titelbestandsbestände')
319
+ )
320
+
287
321
  # hinterer Teil ist ein Wort mit Suffix
288
322
  assert_equal(
289
323
  wd('hasenbraten|KOM', 'hasenbraten|k', 'hase|s+', 'braten|v+'),
@@ -304,7 +338,7 @@ class TestGrammar < LingoTestCase
304
338
 
305
339
  # hinterer Teil ist ein Kompositum nach Bindestrich
306
340
  assert_equal(
307
- wd('arrafat-nachfolgebedarf|KOM', 'arrafat-nachfolgebedarf|k', 'bedarf|s+', 'nachfolge|s+', 'arrafat|x+'),
341
+ wd('arrafat-nachfolgebedarf|KOM', 'arrafat-nachfolgebedarf|k', 'arrafat|x+', 'nachfolge|s+', 'bedarf|s+'),
308
342
  gra.find_compound('arrafat-nachfolgebedarf')
309
343
  )
310
344
 
@@ -317,19 +351,19 @@ class TestGrammar < LingoTestCase
317
351
  # vorderer Teil ist ein Wort mit Suffix => siehe Hasenbraten
318
352
  # vorderer Teil ist ein Kompositum
319
353
  assert_equal(
320
- wd('morgenonkelmantel|KOM', 'morgenonkelmantel|k', 'mantel|s+', 'morgen|s+', 'onkel|s+', 'morgen|w+'),
354
+ wd('morgenonkelmantel|KOM', 'morgenonkelmantel|k', 'morgen|w+', 'morgen|s+', 'onkel|s+', 'mantel|s+'),
321
355
  gra.find_compound('morgenonkelmantel')
322
356
  )
323
357
 
324
358
  # vorderer Teil ist ein TakeItAsIs vor Bindestrich / bindestrichversion
325
359
  assert_equal(
326
- wd('arrafat-nachfolger|KOM', 'arrafat-nachfolger|k', 'nachfolger|s+', 'arrafat|x+'),
360
+ wd('arrafat-nachfolger|KOM', 'arrafat-nachfolger|k', 'arrafat|x+', 'nachfolger|s+'),
327
361
  gra.find_compound('arrafat-nachfolger')
328
362
  )
329
363
 
330
364
  # bindestrichversion zwei-teilig
331
365
  assert_equal(
332
- wd('cd-rom-technologie|KOM', 'cd-rom-technologie|k', 'cd-rom|s+', 'technologie|s+'),
366
+ wd('cd-rom-technologie|KOM', 'cd-rom-technologie|k', 'cd-rom|s+|f', 'cd-rom|s+|m', 'technologie|s+|f'),
333
367
  gra.find_compound('cd-rom-technologie')
334
368
  )
335
369
 
@@ -341,19 +375,45 @@ class TestGrammar < LingoTestCase
341
375
 
342
376
  # normal mit suggestion
343
377
  assert_equal(
344
- wd('benutzerforschung|KOM', 'benutzerforschung|k', 'erforschung|s+', 'benutzen|v+'),
378
+ wd('benutzerforschung|KOM', 'benutzerforschung|k', 'benutzen|v+', 'erforschung|s+'),
345
379
  gra.find_compound('benutzerforschung')
346
380
  )
347
381
  }
348
382
  end
349
383
 
384
+ def test_head
385
+ lg { |gra|
386
+ assert_equal(
387
+ wd('suche|-', 'suche|s', 'suchen|v'),
388
+ gra.find_compound('clustersuche').head
389
+ )
390
+
391
+ assert_equal(
392
+ wd('titel|-', 'titel|s'),
393
+ gra.find_compound('titelkatalogstitel').head
394
+ )
395
+
396
+ assert_equal(
397
+ wd('titel|-', 'titel|s'),
398
+ gra.find_compound('titelkatalogstiteltitel').head
399
+ )
400
+
401
+ assert_equal(
402
+ wd('bestand|-', 'bestand|s', 'bestehen|v'),
403
+ gra.find_compound('titelbestandsbestände').head
404
+ )
405
+
406
+ assert_nil(gra.find_compound('bibliothekskatalög').head)
407
+ }
408
+ end
409
+
350
410
  def test_min_word_size
351
411
  lg { |gra| assert_equal( wd('undsund|?'), gra.find_compound('undsund')) }
352
412
  end
353
413
 
354
414
  def test_max_parts
355
415
  lg { |gra|
356
- assert_equal(wd('baumsbaumsbaum|KOM', 'baumsbaumsbaum|k', 'baum|s+'), gra.find_compound('baumsbaumsbaum'))
416
+ assert_equal(wd('baumsbaumsbaum|KOM', 'baumsbaumsbaum|k', 'baum|s+', 'baum|s+', 'baum|s+'), gra.find_compound('baumsbaumsbaum'))
357
417
  assert_equal(wd('baumsbaumsbaumsbaumsbaumsbaum|?'), gra.find_compound('baumsbaumsbaumsbaumsbaumsbaum'))
358
418
  }
359
419
  end