lingo 1.8.4.2 → 1.8.5

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