patrickod-raspell 1.1

Sign up to get free protection for your applications and to get access to all the features.
data/ext/raspell.c ADDED
@@ -0,0 +1,726 @@
1
+
2
+ #include "raspell.h"
3
+
4
+ extern void Init_dictinfo();
5
+ extern void Init_aspell();
6
+
7
+ void Init_raspell() {
8
+ cAspellError = rb_define_class("AspellError", rb_eStandardError);
9
+ Init_dictinfo();
10
+ Init_aspell();
11
+ }
12
+
13
+ static AspellDictInfo* get_info(VALUE info) {
14
+ AspellDictInfo *result;
15
+ Data_Get_Struct(info, AspellDictInfo, result);
16
+ return result;
17
+ }
18
+
19
+ static VALUE dictinfo_s_new(int argc, VALUE *argv, VALUE klass) {
20
+ rb_raise(rb_eException, "not instantiable");
21
+ }
22
+
23
+ static VALUE dictinfo_name(VALUE self) {
24
+ return rb_str_new2(get_info(self)->name);
25
+ }
26
+
27
+ static VALUE dictinfo_code(VALUE self) {
28
+ return rb_str_new2(get_info(self)->code);
29
+ }
30
+
31
+ static VALUE dictinfo_jargon(VALUE self) {
32
+ return rb_str_new2(get_info(self)->jargon);
33
+ }
34
+
35
+ static VALUE dictinfo_size(VALUE self) {
36
+ return INT2FIX(get_info(self)->size);
37
+ }
38
+
39
+ static VALUE dictinfo_size_str(VALUE self) {
40
+ return rb_str_new2(get_info(self)->size_str);
41
+ }
42
+
43
+ void Init_dictinfo() {
44
+ //CLASS DEFINITION=========================================================
45
+ cDictInfo = rb_define_class("AspellDictInfo", rb_cObject);
46
+
47
+ //CLASS METHODS============================================================
48
+ rb_define_singleton_method(cDictInfo, "new", dictinfo_s_new, 0);
49
+
50
+ //METHODS =================================================================
51
+ rb_define_method(cDictInfo, "name", dictinfo_name, 0);
52
+ rb_define_method(cDictInfo, "code", dictinfo_code, 0);
53
+ rb_define_method(cDictInfo, "jargon", dictinfo_jargon, 0);
54
+ rb_define_method(cDictInfo, "size", dictinfo_size, 0);
55
+ rb_define_method(cDictInfo, "size_str", dictinfo_size_str, 0);
56
+ }
57
+
58
+ extern VALUE rb_cFile;
59
+
60
+ /**
61
+ * This method is called from the garbage collector during finalization.
62
+ * @param p pointer to spellchecker-object.
63
+ */
64
+ static void aspell_free(void *p) {
65
+ delete_aspell_speller(p);
66
+ }
67
+
68
+ /**
69
+ * Check for an error - raise exception if so.
70
+ * @param speller the spellchecker-object.
71
+ * @return void
72
+ * @exception Exception if there was an error.
73
+ */
74
+ static void check_for_error(AspellSpeller * speller) {
75
+ if (aspell_speller_error(speller) != 0) {
76
+ rb_raise(cAspellError, aspell_speller_error_message(speller));
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Set a specific option, that is known by aspell.
82
+ * @param config the config object of a specific spellchecker.
83
+ * @param key the option to set (eg: lang).
84
+ * @param value the value of the option to set (eg: "us_US").
85
+ * @exception Exception if key not known, or value undefined.
86
+ */
87
+ static void set_option(AspellConfig *config, char *key, char *value) {
88
+ //printf("set option: %s = %s\n", key, value);
89
+ if (aspell_config_replace(config, key, value) == 0) {
90
+ rb_raise(cAspellError, aspell_config_error_message(config));
91
+ }
92
+ //check config:
93
+ if (aspell_config_error(config) != 0) {
94
+ rb_raise(cAspellError, aspell_config_error_message(config));
95
+ }
96
+ }
97
+
98
+ static void set_options(AspellConfig *config, VALUE hash) {
99
+ VALUE options = rb_funcall(hash, rb_intern("keys"), 0);
100
+ int count=RARRAY_LEN(options);
101
+ int c = 0;
102
+ //set all values
103
+ while(c<count) {
104
+ //fetch option
105
+ VALUE option = RARRAY_PTR(options)[c];
106
+ VALUE value = rb_funcall(hash, rb_intern("fetch"), 1, option);
107
+ if (TYPE(option)!=T_STRING) rb_raise(cAspellError, "Given key must be a string.");
108
+ if (TYPE(value )!=T_STRING) rb_raise(cAspellError, "Given value must be a string.");
109
+ set_option(config, STR2CSTR(option), STR2CSTR(value));
110
+ c++;
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Extract c-struct speller from ruby object.
116
+ * @param speller the speller as ruby object.
117
+ * @return the speller as c-struct.
118
+ */
119
+ static AspellSpeller* get_speller(VALUE speller) {
120
+ AspellSpeller *result;
121
+ Data_Get_Struct(speller, AspellSpeller, result);
122
+ return result;
123
+ }
124
+
125
+ /**
126
+ * Generate a document checker object from a given speller.
127
+ * @param speller the speller that shall chech a document.
128
+ * @return a fresh document checker.
129
+ */
130
+ static AspellDocumentChecker* get_checker(AspellSpeller *speller) {
131
+ AspellCanHaveError * ret;
132
+ AspellDocumentChecker * checker;
133
+ ret = new_aspell_document_checker(speller);
134
+ if (aspell_error(ret) != 0)
135
+ rb_raise(cAspellError, aspell_error_message(ret));
136
+ checker = to_aspell_document_checker(ret);
137
+ return checker;
138
+ }
139
+
140
+ /**
141
+ * Utility function that wraps a list of words as ruby array of ruby strings.
142
+ * @param list an aspell wordlist.
143
+ * @return an ruby array, containing all words as ruby strings.
144
+ */
145
+ static VALUE get_list(const AspellWordList *list) {
146
+ VALUE result = rb_ary_new2(aspell_word_list_size(list));
147
+ if (list != 0) {
148
+ AspellStringEnumeration * els = aspell_word_list_elements(list);
149
+ const char * word;
150
+ while ( (word = aspell_string_enumeration_next(els)) != 0) {
151
+ rb_ary_push(result, rb_str_new2(word));
152
+ }
153
+ delete_aspell_string_enumeration(els);
154
+ }
155
+ return result;
156
+ }
157
+
158
+ /**
159
+ * Generate a regexp from the given word with word boundaries.
160
+ * @param word the word to match.
161
+ * @return regular expression, matching exactly the word as whole.
162
+ */
163
+ static VALUE get_wordregexp(VALUE word) {
164
+ char *cword = STR2CSTR(word);
165
+ char *result = malloc((strlen(cword)+5)*sizeof(char));
166
+ *result='\0';
167
+ strcat(result, "\\b");
168
+ strcat(result, cword);
169
+ strcat(result, "\\b");
170
+ word = rb_reg_new(result, strlen(result), 0);
171
+ free(result);
172
+ return word;
173
+ }
174
+
175
+
176
+ /**
177
+ * Ctor for aspell objects:
178
+ * Aspell.new(language, jargon, size, encoding)
179
+ * Please note: All parameters are optional. If a parameter is omitted, a default value is assumed from
180
+ * the environment (eg lang from $LANG). To retain default values, you can use nil
181
+ * as value: to set only size: Aspell.new(nil, nil, "80")
182
+ * @param language ISO639 language code plus optional ISO 3166 counry code as string (eg: "de" or "us_US")
183
+ * @param jargon a special jargon of the selected language
184
+ * @param size the size of the dictionary to chose (if there are options)
185
+ * @param encoding the encoding to use
186
+ * @exception Exception if the specified dictionary is not found.
187
+ */
188
+ static VALUE aspell_s_new(int argc, VALUE *argv, VALUE klass) {
189
+ VALUE vlang, vjargon, vsize, vencoding;
190
+ const char *tmp;
191
+ //aspell values
192
+ AspellCanHaveError * ret;
193
+ AspellSpeller * speller;
194
+ AspellConfig * config;
195
+
196
+ //create new config
197
+ config = new_aspell_config();
198
+
199
+ //extract values
200
+ rb_scan_args(argc, argv, "04", &vlang, &vjargon, &vsize, &vencoding);
201
+
202
+ //language:
203
+ if (RTEST(vlang)) set_option(config, "lang", STR2CSTR(vlang));
204
+ //jargon:
205
+ if (RTEST(vjargon)) set_option(config, "jargon", STR2CSTR(vjargon));
206
+ //size:
207
+ if (RTEST(vsize)) set_option(config, "size", STR2CSTR(vsize));
208
+ //encoding:
209
+ if (RTEST(vencoding)) set_option(config, "encoding", STR2CSTR(vencoding));
210
+
211
+ //create speller:
212
+ ret = new_aspell_speller(config);
213
+ delete_aspell_config(config);
214
+ if (aspell_error(ret) != 0) {
215
+ tmp = strdup(aspell_error_message(ret));
216
+ delete_aspell_can_have_error(ret);
217
+ rb_raise(cAspellError, tmp);
218
+ }
219
+
220
+ speller = to_aspell_speller(ret);
221
+
222
+ //wrap pointer
223
+ return Data_Wrap_Struct(klass, 0, aspell_free, speller);
224
+ }
225
+
226
+
227
+
228
+ /**
229
+ * Ctor for aspell objects.
230
+ * This is a custom constructor and takes a hash of config options: key, value pairs.
231
+ * Common use:
232
+ *
233
+ * a = Aspell.new({"lang"=>"de", "jargon"=>"berlin"})
234
+ *
235
+ * For a list of config options, see aspell manual.
236
+ * @param options hash of options
237
+ */
238
+ static VALUE aspell_s_new1(VALUE klass, VALUE options) {
239
+ //aspell values
240
+ AspellCanHaveError * ret;
241
+ AspellSpeller * speller;
242
+ AspellConfig * config;
243
+
244
+ //create new config
245
+ config = new_aspell_config();
246
+
247
+ //set options
248
+ set_options(config, options);
249
+
250
+ //create speller:
251
+ ret = new_aspell_speller(config);
252
+ delete_aspell_config(config);
253
+ if (aspell_error(ret) != 0) {
254
+ const char *tmp = strdup(aspell_error_message(ret));
255
+ delete_aspell_can_have_error(ret);
256
+ rb_raise(cAspellError, tmp);
257
+ }
258
+
259
+ speller = to_aspell_speller(ret);
260
+
261
+ //wrap pointer
262
+ return Data_Wrap_Struct(klass, 0, aspell_free, speller);
263
+ }
264
+
265
+ /**
266
+ * List all available dictionaries.
267
+ * @param class object
268
+ * @return array of AspellDictInfo objects.
269
+ */
270
+ static VALUE aspell_s_list_dicts(VALUE klass) {
271
+ AspellConfig * config;
272
+ AspellDictInfoList * dlist;
273
+ AspellDictInfoEnumeration * dels;
274
+ const AspellDictInfo * entry;
275
+ VALUE result = rb_ary_new();
276
+
277
+ //get a list of dictionaries
278
+ config = new_aspell_config();
279
+ dlist = get_aspell_dict_info_list(config);
280
+ delete_aspell_config(config);
281
+
282
+ //iterate over list - fill ruby array
283
+ dels = aspell_dict_info_list_elements(dlist);
284
+ while ( (entry = aspell_dict_info_enumeration_next(dels)) != 0) {
285
+ rb_ary_push(result, Data_Wrap_Struct(cDictInfo, 0, 0, (AspellDictInfo *)entry));
286
+ }
287
+ delete_aspell_dict_info_enumeration(dels);
288
+ return result;
289
+ }
290
+
291
+ /**
292
+ * @see set_option.
293
+ */
294
+ static VALUE aspell_set_option(VALUE self, VALUE option, VALUE value) {
295
+ AspellSpeller *speller = get_speller(self);
296
+ set_option(aspell_speller_config(speller), STR2CSTR(option), STR2CSTR(value));
297
+ return self;
298
+ }
299
+
300
+
301
+ /**
302
+ * Delete an option.
303
+ * @param option optionstring to remove from the options.
304
+ */
305
+ static VALUE aspell_remove_option(VALUE self, VALUE option) {
306
+ AspellSpeller *speller = get_speller(self);
307
+ aspell_config_remove(aspell_speller_config(speller), STR2CSTR(option));
308
+ return self;
309
+ }
310
+
311
+ /**
312
+ * To set the mode, words are suggested.
313
+ * @param one of Aspell::[ULTRA|FAST|NORMAL|BADSPELLERS]
314
+ */
315
+ static VALUE aspell_set_suggestion_mode(VALUE self, VALUE value) {
316
+ AspellSpeller *speller = get_speller(self);
317
+ set_option(aspell_speller_config(speller), "sug-mode", STR2CSTR(value));
318
+ return self;
319
+ }
320
+
321
+ /**
322
+ * Returns the personal wordlist as array of strings.
323
+ * @return array of strings
324
+ */
325
+ static VALUE aspell_personal_wordlist(VALUE self) {
326
+ AspellSpeller *speller = get_speller(self);
327
+ return get_list(aspell_speller_personal_word_list(speller));
328
+ }
329
+
330
+ /**
331
+ * Returns the session wordlist as array of strings.
332
+ * @return array of strings
333
+ */
334
+ static VALUE aspell_session_wordlist(VALUE self) {
335
+ AspellSpeller *speller = get_speller(self);
336
+ return get_list(aspell_speller_session_word_list(speller));
337
+ }
338
+
339
+ /**
340
+ * Returns the main wordlist as array of strings.
341
+ * @return array of strings
342
+ */
343
+ static VALUE aspell_main_wordlist(VALUE self) {
344
+ AspellSpeller *speller = get_speller(self);
345
+ return get_list(aspell_speller_main_word_list(speller));
346
+ }
347
+
348
+ /**
349
+ * Synchronize all wordlists with the current session.
350
+ */
351
+ static VALUE aspell_save_all_wordlists(VALUE self) {
352
+ AspellSpeller *speller = get_speller(self);
353
+ aspell_speller_save_all_word_lists(speller);
354
+ check_for_error(speller);
355
+ return self;
356
+ }
357
+
358
+ /**
359
+ * Remove all words inside session.
360
+ */
361
+ static VALUE aspell_clear_session(VALUE self) {
362
+ AspellSpeller *speller = get_speller(self);
363
+ aspell_speller_clear_session(speller);
364
+ check_for_error(speller);
365
+ return self;
366
+ }
367
+
368
+ /**
369
+ * Suggest words for the given misspelled word.
370
+ * @param word the misspelled word.
371
+ * @return array of strings.
372
+ */
373
+ static VALUE aspell_suggest(VALUE self, VALUE word) {
374
+ AspellSpeller *speller = get_speller(self);
375
+ return get_list(aspell_speller_suggest(speller, STR2CSTR(word), -1));
376
+ }
377
+
378
+ /**
379
+ * Add a given word to the list of known words inside my private dictionary.
380
+ * You have to call aspell_save_all_wordlists to make sure the list gets persistent.
381
+ * @param word the word to add.
382
+ */
383
+ static VALUE aspell_add_to_personal(VALUE self, VALUE word) {
384
+ AspellSpeller *speller = get_speller(self);
385
+ aspell_speller_add_to_personal(speller, STR2CSTR(word), -1);
386
+ check_for_error(speller);
387
+ return self;
388
+ }
389
+
390
+ /**
391
+ * Add a given word to the list of known words just for the lifetime of this object.
392
+ * @param word the word to add.
393
+ */
394
+ static VALUE aspell_add_to_session(VALUE self, VALUE word) {
395
+ AspellSpeller *speller = get_speller(self);
396
+ aspell_speller_add_to_session(speller, STR2CSTR(word), -1);
397
+ check_for_error(speller);
398
+ return self;
399
+ }
400
+
401
+ /**
402
+ * Retrieve the value of a specific option.
403
+ * The options are listed inside
404
+ * Aspell::[DictionaryOptions|CheckerOptions|FilterOptions|RunTogetherOptions|MiscOptions|UtilityOptions]
405
+ * @param word the option as string.
406
+ */
407
+ static VALUE aspell_conf_retrieve(VALUE self, VALUE key) {
408
+ AspellSpeller *speller = get_speller(self);
409
+ AspellConfig *config = aspell_speller_config(speller);
410
+ VALUE result = rb_str_new2(aspell_config_retrieve(config, STR2CSTR(key)));
411
+ if (aspell_config_error(config) != 0) {
412
+ rb_raise(cAspellError, aspell_config_error_message(config));
413
+ }
414
+ return result;
415
+ }
416
+
417
+ /**
418
+ * Retrieve the value of a specific option as list.
419
+ * @param word the option as string.
420
+ */
421
+ static VALUE aspell_conf_retrieve_list(VALUE self, VALUE key) {
422
+ AspellSpeller *speller = get_speller(self);
423
+ AspellConfig *config = aspell_speller_config(speller);
424
+ AspellStringList * list = new_aspell_string_list();
425
+ AspellMutableContainer * container = aspell_string_list_to_mutable_container(list);
426
+ AspellStringEnumeration * els;
427
+ VALUE result = rb_ary_new();
428
+ const char *option_value;
429
+
430
+ //retrieve list
431
+ aspell_config_retrieve_list(config, STR2CSTR(key), container);
432
+ //check for error
433
+ if (aspell_config_error(config) != 0) {
434
+ char *tmp = strdup(aspell_config_error_message(config));
435
+ delete_aspell_string_list(list);
436
+ rb_raise( cAspellError, tmp);
437
+ }
438
+
439
+ //iterate over list
440
+ els = aspell_string_list_elements(list);
441
+ while ( (option_value = aspell_string_enumeration_next(els)) != 0) {
442
+ //push the option value to result
443
+ rb_ary_push(result, rb_str_new2(option_value));
444
+ }
445
+ //free list
446
+ delete_aspell_string_enumeration(els);
447
+ delete_aspell_string_list(list);
448
+
449
+ return result;
450
+ }
451
+
452
+ /**
453
+ * Simply dump config.
454
+ * Not very useful at all.
455
+ */
456
+ static VALUE aspell_dump_config(VALUE self) {
457
+ AspellSpeller *speller = get_speller(self);
458
+ AspellConfig *config = aspell_speller_config(speller);
459
+ AspellKeyInfoEnumeration * key_list = aspell_config_possible_elements( config, 0 );
460
+ const AspellKeyInfo * entry;
461
+
462
+ while ( (entry = aspell_key_info_enumeration_next(key_list) ) ) {
463
+ printf("%20s: %s\n", entry->name, aspell_config_retrieve(config, entry->name) );
464
+ }
465
+ delete_aspell_key_info_enumeration(key_list);
466
+ return self;
467
+ }
468
+
469
+ /**
470
+ * Check a given word for correctness.
471
+ * @param word the word to check
472
+ * @return true if the word is correct, otherwise false.
473
+ */
474
+ static VALUE aspell_check(VALUE self, VALUE word) {
475
+ AspellSpeller *speller = get_speller(self);
476
+ VALUE result = Qfalse;
477
+ int code = aspell_speller_check(speller, STR2CSTR(word), -1);
478
+ if (code == 1)
479
+ result = Qtrue;
480
+ else if (code == 0)
481
+ result = Qfalse;
482
+ else
483
+ rb_raise( cAspellError, aspell_speller_error_message(speller));
484
+ return result;
485
+ }
486
+
487
+ /**
488
+ * This method will check an array of strings for misspelled words.
489
+ * This method needs a block to work proper. Each misspelled word is yielded,
490
+ * a correct word as result from the block is assumed.
491
+ * Common use:
492
+ *
493
+ * a = Aspell.new(...)
494
+ * text = ...
495
+ * a.correct_lines(text) { |badword|
496
+ * puts "Error: #{badword}\n"
497
+ * puts a.suggest(badword).join(" | ")
498
+ * gets #the input is returned as right word
499
+ * }
500
+ *
501
+ * @param ary the array of strings to check.
502
+ * @result an array holding all lines with corrected words.
503
+ */
504
+ static VALUE aspell_correct_lines(VALUE self, VALUE ary) {
505
+ VALUE result = ary;
506
+ if (rb_block_given_p()) {
507
+ //create checker
508
+ AspellSpeller *speller = get_speller(self);
509
+ AspellDocumentChecker * checker = get_checker(speller);
510
+ AspellToken token;
511
+ //some tmp values
512
+ VALUE vline, sline;
513
+ VALUE word, rword;
514
+ char *line;
515
+ int count=RARRAY_LEN(ary);
516
+ int c=0;
517
+ //create new result array
518
+ result = rb_ary_new();
519
+ //iterate over array
520
+ while(c<count) {
521
+ int offset=0;
522
+ //fetch line
523
+ vline = RARRAY_PTR(ary)[c];
524
+ //save line
525
+ sline = rb_funcall(vline, rb_intern("dup"), 0);
526
+ //c representation
527
+ line = STR2CSTR(vline);
528
+ //process line
529
+ aspell_document_checker_process(checker, line, -1);
530
+ //iterate over all misspelled words
531
+ while (token = aspell_document_checker_next_misspelling(checker), token.len != 0) {
532
+ //extract word by start/length qualifier
533
+ word = rb_funcall(vline, rb_intern("[]"), 2, INT2FIX(token.offset), INT2FIX(token.len));
534
+ //get the right word from the block
535
+ rword = rb_yield(word);
536
+ //nil -> do nothing
537
+ if(rword == Qnil) continue;
538
+ //check for string
539
+ if (TYPE(rword) != T_STRING) rb_raise(cAspellError, "Need a String to substitute");
540
+ //chomp the string
541
+ rb_funcall(rword, rb_intern("chomp!"), 0);
542
+ //empty string -> do nothing
543
+ if(strlen(STR2CSTR(rword)) == 0) continue;
544
+ //remember word for later suggestion
545
+ aspell_speller_store_replacement(speller, STR2CSTR(word), -1, STR2CSTR(rword), -1);
546
+ //substitute the word by replacement
547
+ rb_funcall(sline, rb_intern("[]="), 3, INT2FIX(token.offset+offset), INT2FIX(token.len), rword);
548
+ //adjust offset
549
+ offset += strlen(STR2CSTR(rword))-strlen(STR2CSTR(word));
550
+ //printf("replace >%s< with >%s< (offset now %d)\n", STR2CSTR(word), STR2CSTR(rword), offset);
551
+ }
552
+ //push the substituted line to result
553
+ rb_ary_push(result, sline);
554
+ c++;
555
+ }
556
+ //free checker
557
+ delete_aspell_document_checker(checker);
558
+ } else {
559
+ rb_raise(cAspellError, "No block given. How to correct?");
560
+ }
561
+ return result;
562
+ }
563
+
564
+ /**
565
+ * Remember a correction.
566
+ * This affects the suggestion of other words to fit this correction.
567
+ * @param badword the bad spelled word as string.
568
+ * @param badword the correction of the bad spelled word as string.
569
+ * @result self
570
+ */
571
+ static VALUE aspell_store_replacement(VALUE self, VALUE badword, VALUE rightword) {
572
+ AspellSpeller *speller = get_speller(self);
573
+ aspell_speller_store_replacement(speller, STR2CSTR(badword), -1, STR2CSTR(rightword), -1);
574
+ return self;
575
+ }
576
+
577
+ /**
578
+ * Simple utility function to correct a file.
579
+ * The file gets read, content will be checked and write back.
580
+ * Please note: This method will change the file! - no backup and of course: no warranty!
581
+ * @param filename the name of the file as String.
582
+ * @exception Exception due to lack of read/write permissions.
583
+ */
584
+ static VALUE aspell_correct_file(VALUE self, VALUE filename) {
585
+ if (rb_block_given_p()) {
586
+ VALUE content = rb_funcall(rb_cFile, rb_intern("readlines"), 1, filename);
587
+ VALUE newcontent = aspell_correct_lines(self, content);
588
+ VALUE file = rb_file_open(STR2CSTR(filename), "w+");
589
+ rb_funcall(file, rb_intern("write"), 1, newcontent);
590
+ rb_funcall(file, rb_intern("close"), 0);
591
+ } else {
592
+ rb_raise(cAspellError, "No block given. How to correct?");
593
+ }
594
+ return self;
595
+
596
+ }
597
+
598
+ /**
599
+ * Return a list of all misspelled words inside a given array of strings.
600
+ * @param ary an array of strings to check for.
601
+ * @return array of strings: words that are misspelled.
602
+ */
603
+ static VALUE aspell_list_misspelled(VALUE self, VALUE ary) {
604
+ VALUE result = rb_hash_new();
605
+ //create checker
606
+ AspellSpeller *speller = get_speller(self);
607
+ AspellDocumentChecker * checker = get_checker(speller);
608
+ AspellToken token;
609
+ VALUE word, vline;
610
+ int count=RARRAY_LEN(ary);
611
+ int c=0;
612
+ //iterate over array
613
+ while(c<count) {
614
+ //process line
615
+ vline = RARRAY_PTR(ary)[c];
616
+ aspell_document_checker_process(checker, STR2CSTR(vline), -1);
617
+ //iterate over all misspelled words
618
+ while (token = aspell_document_checker_next_misspelling(checker), token.len != 0) {
619
+ //extract word by start/length qualifier
620
+ word = rb_funcall(vline, rb_intern("[]"), 2, INT2FIX(token.offset), INT2FIX(token.len));
621
+ rb_hash_aset(result, word, Qnil);
622
+ //yield block, if given
623
+ if (rb_block_given_p())
624
+ rb_yield(word);
625
+ }
626
+ c++;
627
+ }
628
+ //free checker
629
+ delete_aspell_document_checker(checker);
630
+ result = rb_funcall(result, rb_intern("keys"), 0);
631
+ return result;
632
+ }
633
+
634
+ void Init_aspell() {
635
+ //CLASS DEFINITION=========================================================
636
+ cAspell = rb_define_class("Aspell", rb_cObject);
637
+
638
+ //CONSTANTS================================================================
639
+ rb_define_const(cAspell, "ULTRA", rb_str_new2("ultra"));
640
+ rb_define_const(cAspell, "FAST", rb_str_new2("fast"));
641
+ rb_define_const(cAspell, "NORMAL", rb_str_new2("normal"));
642
+ rb_define_const(cAspell, "BADSPELLERS", rb_str_new2("bad-spellers"));
643
+ rb_define_const(cAspell, "DictionaryOptions", rb_ary_new3( 11,
644
+ rb_str_new2("master"),
645
+ rb_str_new2("dict-dir"),
646
+ rb_str_new2("lang"),
647
+ rb_str_new2("size"),
648
+ rb_str_new2("jargon"),
649
+ rb_str_new2("word-list-path"),
650
+ rb_str_new2("module-search-order"),
651
+ rb_str_new2("personal"),
652
+ rb_str_new2("repl"),
653
+ rb_str_new2("extra-dicts"),
654
+ rb_str_new2("strip-accents")));
655
+ rb_define_const(cAspell, "CheckerOptions", rb_ary_new3( 11,
656
+ rb_str_new2("ignore"),
657
+ rb_str_new2("ignore-case"),
658
+ rb_str_new2("ignore-accents"),
659
+ rb_str_new2("ignore-repl"),
660
+ rb_str_new2("save-repl"),
661
+ rb_str_new2("sug-mode"),
662
+ rb_str_new2("module-search-order"),
663
+ rb_str_new2("personal"),
664
+ rb_str_new2("repl"),
665
+ rb_str_new2("extra-dicts"),
666
+ rb_str_new2("strip-accents")));
667
+ rb_define_const(cAspell, "FilterOptions", rb_ary_new3( 10,
668
+ rb_str_new2("filter"),
669
+ rb_str_new2("mode"),
670
+ rb_str_new2("encoding"),
671
+ rb_str_new2("add-email-quote"),
672
+ rb_str_new2("rem-email-quote"),
673
+ rb_str_new2("email-margin"),
674
+ rb_str_new2("sgml-check"),
675
+ rb_str_new2("sgml-extension"),
676
+ rb_str_new2("tex-command"),
677
+ rb_str_new2("tex-check-command")));
678
+ rb_define_const(cAspell, "RunTogetherOptions", rb_ary_new3( 3,
679
+ rb_str_new2("run-together"),
680
+ rb_str_new2("run-together-limit"),
681
+ rb_str_new2("run-together-min")));
682
+ rb_define_const(cAspell, "MiscOptions", rb_ary_new3( 8,
683
+ rb_str_new2("conf"),
684
+ rb_str_new2("conf-dir"),
685
+ rb_str_new2("data-dir"),
686
+ rb_str_new2("local-data-dir"),
687
+ rb_str_new2("home-dir"),
688
+ rb_str_new2("per-conf"),
689
+ rb_str_new2("prefix"),
690
+ rb_str_new2("set-prefix")));
691
+
692
+ rb_define_const(cAspell, "UtilityOptions", rb_ary_new3( 4,
693
+ rb_str_new2("backup"),
694
+ rb_str_new2("time"),
695
+ rb_str_new2("reverse"),
696
+ rb_str_new2("keymapping")));
697
+
698
+ //CLASS METHODS============================================================
699
+ rb_define_singleton_method(cAspell, "new", aspell_s_new, -1);
700
+ rb_define_singleton_method(cAspell, "new1", aspell_s_new1, 1);
701
+ rb_define_singleton_method(cAspell, "list_dicts", aspell_s_list_dicts, 0);
702
+
703
+ //METHODS =================================================================
704
+ rb_define_method(cAspell, "add_to_personal", aspell_add_to_personal, 1);
705
+ rb_define_method(cAspell, "add_to_session", aspell_add_to_personal, 1);
706
+ rb_define_method(cAspell, "check", aspell_check, 1);
707
+ rb_define_method(cAspell, "correct_lines", aspell_correct_lines, 1);
708
+ rb_define_method(cAspell, "correct_file", aspell_correct_file, 1);
709
+ rb_define_method(cAspell, "clear_session", aspell_clear_session, 0);
710
+ rb_define_method(cAspell, "dump_config", aspell_dump_config, 0);
711
+ rb_define_method(cAspell, "list_misspelled", aspell_list_misspelled, 1);
712
+ //This seems not to be very useful ...
713
+ //rb_define_method(cAspell, "main_wordlist", aspell_main_wordlist, 0);
714
+ rb_define_method(cAspell, "personal_wordlist", aspell_personal_wordlist, 0);
715
+ rb_define_method(cAspell, "save_all_word_lists", aspell_save_all_wordlists, 0);
716
+ rb_define_method(cAspell, "session_wordlist", aspell_session_wordlist, 0);
717
+ rb_define_method(cAspell, "set_option", aspell_set_option, 2);
718
+ rb_define_method(cAspell, "store_replacement", aspell_store_replacement, 2);
719
+ rb_define_method(cAspell, "remove_option", aspell_remove_option, 1);
720
+ rb_define_method(cAspell, "get_option", aspell_conf_retrieve, 1);
721
+ rb_define_method(cAspell, "get_option_as_list", aspell_conf_retrieve_list, 1);
722
+ rb_define_method(cAspell, "suggest", aspell_suggest, 1);
723
+ rb_define_method(cAspell, "suggestion_mode=", aspell_set_suggestion_mode, 1);
724
+ }
725
+
726
+