ffi-hunspell-wtchappell 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7239f5e7cc9fb2cd74e51ad31d31d1f2ef74dd3482e74245ea95fb2e96144a91
4
+ data.tar.gz: 22c9a4709bd64c9ad28434c08442dc9715baefc775fd8b22e288ebb8cbb5e33e
5
+ SHA512:
6
+ metadata.gz: 06ca100581cd5d9ef888f9720ca535def2af26d414f057ddebd09269ae4012ef312d0009722486bdf81d2952a0c1f80372de8c09e9089f42a0462a73266b91a9
7
+ data.tar.gz: adcaa5cdf288ed4856605ce6439867aa39c0576dc1cd9e7bfe40ecf70cdfb487f9de2f16faffbfbdb3aff91cb4b9e613f4a7e189a358af4d836891f58986e07c
File without changes
@@ -0,0 +1,4 @@
1
+ doc
2
+ pkg
3
+ .bundle
4
+ .yardoc
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ before_install:
3
+ - sudo apt-get install libhunspell-dev hunspell-en-us
4
+ - gem install ffi rubygems-tasks rspec yard
5
+ rvm:
6
+ - 1.9.3
7
+ - 2.3.0
8
+ - jruby
9
+ - rbx
10
+ matrix:
11
+ allow_failures:
12
+ - rvm: rbx
13
+ script: rake spec
@@ -0,0 +1 @@
1
+ --markup markdown --title 'FFI Hunspell Documentation' --protected --files ChangeLog.md,LICENSE.txt
@@ -0,0 +1,71 @@
1
+ ### 0.4.0 / 2017-04-21
2
+
3
+ * Added support for libhunspell-1.6.
4
+ * Added support for libhunspell-1.5 (@trench8891).
5
+ * Added support for libhunspell-1.4 (@willmoorefyi).
6
+ * Renamed `#add_affix` to {FFI::Hunspell::Dictionary#add_with_affix}
7
+ (@cdchapman).
8
+
9
+ ### 0.3.1 / 2016-01-14
10
+
11
+ * Prefer loading hunspell-1.3 over hunspell-1.2, if both are installed.
12
+ * Support auto-detection of hunspell installed by homebrew (@forward3d).
13
+
14
+ ### 0.3.0 / 2013-05-01
15
+
16
+ * Detect Ubuntu's hunspell directory (`/usr/share/hunspell`).
17
+ * {FFI::Hunspell::Dictionary#encoding} now returns an `Encoding` object.
18
+ * Encode Strings returned from {FFI::Hunspell::Dictionary#stem} and
19
+ {FFI::Hunspell::Dictionary#suggest} to match the dictionary's native
20
+ encoding.
21
+
22
+ ### 0.2.6 / 2013-02-05
23
+
24
+ * Removed the env dependency.
25
+ * Check the returned count from `Hunsepll_stem` in
26
+ {FFI::Hunspell::Dictionary#stem}.
27
+ * Check the returned count from `Hunspell_suggest` in
28
+ {FFI::Hunspell::Dictionary#suggest}.
29
+
30
+ ### 0.2.5 / 2012-05-11
31
+
32
+ * Load `libhunspell-1.2.so.0` if `libhunspell-1.2.so` cannot be found.
33
+ * Load `libhunspell-1.3.so.0` if `libhunspell-1.3.so` cannot be found.
34
+
35
+ ### 0.2.4 / 2012-04-27
36
+
37
+ * Require ffi ~> 1.0.
38
+ * Attempt loading `libhunspell-1.2` and `libhunspell-1.3`.
39
+
40
+ ### 0.2.3 / 2011-02-02
41
+
42
+ * Require ffi >= 0.6.0 and <= 1.1.0:
43
+ * JRuby requires ffi >= 1.0.0.
44
+ * A lot of projects still require ffi ~> 0.6.0.
45
+
46
+ ### 0.2.2 / 2011-01-25
47
+
48
+ * Added {FFI::Hunspell::USER_DIR}.
49
+ * Added {FFI::Hunspell::KNOWN_DIRECTORIES}, containing known dictionary
50
+ directories used by Debian, Fedora and Mac Ports.
51
+ * Have {FFI::Hunspell.directories} return the dictionary directories found
52
+ on the system.
53
+
54
+ ### 0.2.1 / 2011-01-23
55
+
56
+ * Require env ~> 0.1.2.
57
+ * Use `Env.lang` to get the default language.
58
+ * Updated the Copyright years.
59
+
60
+ ### 0.2.0 / 2011-01-22
61
+
62
+ * Added {FFI::Hunspell.lang}.
63
+ * Added {FFI::Hunspell.lang=}.
64
+ * Added {FFI::Hunspell.directories}.
65
+ * Have {FFI::Hunspell::Dictionary.open} accept a language name, and search
66
+ {FFI::Hunspell.directories} for the dictionary files.
67
+
68
+ ### 0.1.0 / 2010-10-05
69
+
70
+ * Initial release.
71
+
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010-2016 Hal Brodigan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ 'Software'), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,67 @@
1
+ # ffi-hunspell
2
+
3
+ * [Source](https://github.com/postmodern/ffi-hunspell)
4
+ * [Issues](https://github.com/postmodern/ffi-hunspell/issues)
5
+ * [Documentation](http://rubydoc.info/gems/ffi-hunspell/frames)
6
+ * [Email](postmodern.mod3 at gmail.com)
7
+
8
+ [![Build Status](https://secure.travis-ci.org/postmodern/ffi-hunspell.png?branch=master)](https://travis-ci.org/postmodern/ffi-hunspell)
9
+
10
+ ## Description
11
+
12
+ Ruby FFI bindings for [Hunspell][libhunspell].
13
+
14
+ ## Examples
15
+
16
+ Open a dictionary:
17
+ ```rb
18
+ require 'ffi/hunspell'
19
+
20
+ FFI::Hunspell.dict do |dict|
21
+ # ...
22
+ end
23
+
24
+ FFI::Hunspell.dict('en_GB') do |dict|
25
+ # ...
26
+ end
27
+
28
+ dict = FFI::Hunspell.dict('en_GB')
29
+ # ...
30
+ dict.close
31
+ ```
32
+
33
+ Check if a word is valid:
34
+ ```rb
35
+ dict.check?('dog')
36
+ # => true
37
+
38
+ dict.check?('d0g')
39
+ # => false
40
+ ```
41
+ Find the stems of a word:
42
+ ```rb
43
+ dict.stem('dogs')
44
+ # => ["dog"]
45
+ ```
46
+ Suggest alternate spellings for a word:
47
+ ```rb
48
+ dict.suggest('arbitrage')
49
+ # => ["arbitrage", "arbitrages", "arbitrager", "arbitraged", "arbitrate"]
50
+ ```
51
+ ## Requirements
52
+
53
+ * [libhunspell] >= 1.2.0
54
+ * [ffi] ~> 1.0
55
+
56
+ ## Install
57
+ ```sh
58
+ $ gem install ffi-hunspell
59
+ ```
60
+ ## License
61
+
62
+ Copyright (c) 2010-2016 Hal Brodigan
63
+
64
+ See {file:LICENSE.txt} for license information.
65
+
66
+ [libhunspell]: http://hunspell.sourceforge.net/
67
+ [ffi]: https://github.com/ffi/ffi
@@ -0,0 +1,33 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'rubygems/tasks'
6
+
7
+ Gem::Tasks.new
8
+ rescue LoadError => e
9
+ warn e.message
10
+ warn "Run `gem install rubygems-tasks` to install 'rubygems/tasks'."
11
+ end
12
+
13
+ begin
14
+ require 'rspec/core/rake_task'
15
+
16
+ RSpec::Core::RakeTask.new
17
+ rescue LoadError => e
18
+ task :spec do
19
+ abort "Please run `gem install rspec` to install RSpec."
20
+ end
21
+ end
22
+ task :test => :spec
23
+ task :default => :spec
24
+
25
+ begin
26
+ require 'yard'
27
+
28
+ YARD::Rake::YardocTask.new
29
+ rescue LoadError => e
30
+ task :yard do
31
+ abort "Please run `gem install yard` to install YARD."
32
+ end
33
+ end
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gemspec = YAML.load_file('gemspec.yml')
7
+
8
+ gem.name = gemspec.fetch('name')
9
+ gem.version = gemspec.fetch('version') do
10
+ lib_dir = File.join(File.dirname(__FILE__),'lib')
11
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
12
+
13
+ require 'ffi/hunspell/version'
14
+ FFI::Hunspell::VERSION
15
+ end
16
+
17
+ gem.summary = gemspec['summary']
18
+ gem.description = gemspec['description']
19
+ gem.licenses = Array(gemspec['license'])
20
+ gem.authors = Array(gemspec['authors'])
21
+ gem.email = gemspec['email']
22
+ gem.homepage = gemspec['homepage']
23
+
24
+ glob = lambda { |patterns| gem.files & Dir[*patterns] }
25
+
26
+ gem.files = `git ls-files`.split($/)
27
+ gem.files = glob[gemspec['files']] if gemspec['files']
28
+
29
+ gem.executables = gemspec.fetch('executables') do
30
+ glob['bin/*'].map { |path| File.basename(path) }
31
+ end
32
+ gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
33
+
34
+ gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
35
+ gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
36
+ gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
37
+
38
+ gem.require_paths = Array(gemspec.fetch('require_paths') {
39
+ %w[ext lib].select { |dir| File.directory?(dir) }
40
+ })
41
+
42
+ gem.requirements = gemspec['requirements']
43
+ gem.required_ruby_version = gemspec['required_ruby_version']
44
+ gem.required_rubygems_version = gemspec['required_rubygems_version']
45
+ gem.post_install_message = gemspec['post_install_message']
46
+
47
+ split = lambda { |string| string.split(/,\s*/) }
48
+
49
+ if gemspec['dependencies']
50
+ gemspec['dependencies'].each do |name,versions|
51
+ gem.add_dependency(name,split[versions])
52
+ end
53
+ end
54
+
55
+ if gemspec['development_dependencies']
56
+ gemspec['development_dependencies'].each do |name,versions|
57
+ gem.add_development_dependency(name,split[versions])
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,24 @@
1
+ name: ffi-hunspell-wtchappell
2
+ version: 0.4.0
3
+ summary: FFI bindings for Hunspell
4
+ description: Ruby FFI bindings for the Hunspell spell checker and multi-dictionary support.
5
+ license: MIT
6
+ authors:
7
+ - Postmodern
8
+ - cdchapman
9
+ - wtchappell
10
+ email: wtchappell@gmail.com
11
+ homepage: https://github.com/wtchappell/ffi-hunspell
12
+ has_yard: true
13
+
14
+ requirements: libhunspell >= 1.2.0
15
+
16
+ required_ruby_version: ">= 1.9.1"
17
+
18
+ dependencies:
19
+ ffi: ~> 1.0
20
+
21
+ development_dependencies:
22
+ rubygems-tasks: ~> 0.1
23
+ rspec: ~> 3.0
24
+ yard: ~> 0.7
@@ -0,0 +1,2 @@
1
+ require 'ffi/hunspell/hunspell'
2
+ require 'ffi/hunspell/dictionary'
@@ -0,0 +1,278 @@
1
+ require 'ffi/hunspell/hunspell'
2
+
3
+ module FFI
4
+ module Hunspell
5
+ #
6
+ # Represents a dictionary for a specific language.
7
+ #
8
+ class Dictionary
9
+
10
+ # The affix file extension
11
+ AFF_EXT = 'aff'
12
+
13
+ # The dictionary file extension
14
+ DIC_EXT = 'dic'
15
+
16
+ #
17
+ # Creates a new dictionary.
18
+ #
19
+ # @param [String] affix_path
20
+ # The path to the `.aff` file.
21
+ #
22
+ # @param [String] dic_path
23
+ # The path to the `.dic` file.
24
+ #
25
+ # @param [String] key
26
+ # The optional key for encrypted dictionary files.
27
+ #
28
+ # @raise [RuntimeError]
29
+ # Either the `.aff` or `.dic` files did not exist.
30
+ #
31
+ def initialize(affix_path,dic_path,key=nil)
32
+ unless File.file?(affix_path)
33
+ raise("invalid affix path #{affix_path.inspect}")
34
+ end
35
+
36
+ unless File.file?(dic_path)
37
+ raise("invalid dic path #{dic_path.inspect}")
38
+ end
39
+
40
+ @ptr = if key then Hunspell.Hunspell_create_key(affix_path,dic_path,key)
41
+ else Hunspell.Hunspell_create(affix_path,dic_path)
42
+ end
43
+ end
44
+
45
+ #
46
+ # Opens a Hunspell dictionary.
47
+ #
48
+ # @param [Symbol, String] name
49
+ # The name of the dictionary to open.
50
+ #
51
+ # @yield [dict]
52
+ # The given block will be passed the Hunspell dictionary.
53
+ #
54
+ # @yieldparam [Dictionary] dict
55
+ # The opened dictionary.
56
+ #
57
+ # @return [Dictionary]
58
+ # If no block is given, the open dictionary will be returned.
59
+ #
60
+ # @raise [ArgumentError]
61
+ # The dictionary files could not be found in any of the directories.
62
+ #
63
+ def self.open(name)
64
+ name = name.to_s
65
+
66
+ Hunspell.directories.each do |dir|
67
+ affix_path = File.join(dir,"#{name}.#{AFF_EXT}")
68
+ dic_path = File.join(dir,"#{name}.#{DIC_EXT}")
69
+
70
+ if (File.file?(affix_path) && File.file?(dic_path))
71
+ dict = self.new(affix_path,dic_path)
72
+
73
+ if block_given?
74
+ yield dict
75
+
76
+ dict.close
77
+ return nil
78
+ else
79
+ return dict
80
+ end
81
+ end
82
+ end
83
+
84
+ raise(ArgumentError,"unable to find the dictionary #{name.dump} in any of the directories")
85
+ end
86
+
87
+ #
88
+ # Determines if the dictionary is closed.
89
+ #
90
+ # @return [Boolean]
91
+ # Specifies whether the dictionary was closed.
92
+ #
93
+ def closed?
94
+ @ptr.nil?
95
+ end
96
+
97
+ #
98
+ # The encoding of the dictionary file.
99
+ #
100
+ # @return [Encoding]
101
+ # The encoding of the dictionary file.
102
+ #
103
+ def encoding
104
+ @encoding ||= Encoding.const_get(
105
+ Hunspell.Hunspell_get_dic_encoding(self).gsub('-','_')
106
+ )
107
+ end
108
+
109
+ #
110
+ # Adds a word to the dictionary.
111
+ #
112
+ # @param [#to_s] word
113
+ # The word to add to the dictionary.
114
+ #
115
+ def add(word)
116
+ Hunspell.Hunspell_add(self,word.to_s)
117
+ end
118
+
119
+ #
120
+ # Adds a word to the dictionary with affix flags.
121
+ #
122
+ # @param [#to_s] word
123
+ # The word to add to the dictionary.
124
+ #
125
+ # @param [#to_s] example
126
+ # Affix flags.
127
+ #
128
+ # @since 0.4.0
129
+ #
130
+ def add_with_affix(word,example)
131
+ Hunspell.Hunspell_add_with_affix(self,word.to_s,example.to_s)
132
+ end
133
+
134
+ #
135
+ # @deprecated Please use {#add_with_affix} instead.
136
+ #
137
+ alias << add
138
+
139
+ def add_affix(word,example)
140
+ add_with_affix(word,example)
141
+ end
142
+
143
+ #
144
+ # Load an extra dictionary file. The extra dictionaries use the
145
+ # affix file of the allocated Hunspell object.
146
+ #
147
+ # Maximal number of extra dictionaries is limited in the source code (20)
148
+ #
149
+ # @param [String] dic_path
150
+ # The path to the extra `.dic` file.
151
+ #
152
+ # @raise [RuntimeError]
153
+ # The extra `.dic` file did not exist.
154
+ #
155
+ #
156
+ def add_dic(dic_path)
157
+ unless File.file?(dic_path)
158
+ raise("invalid extra dictionary path #{dic_path.inspect}")
159
+ end
160
+
161
+ Hunspell.Hunspell_add_dic(self,dic_path)
162
+ end
163
+
164
+ #
165
+ # Removes a word from the dictionary.
166
+ #
167
+ # @param [#to_s] word
168
+ # The word to remove.
169
+ #
170
+ def remove(word)
171
+ Hunspell.Hunspell_remove(self,word.to_s)
172
+ end
173
+
174
+ alias delete remove
175
+
176
+ #
177
+ # Checks if the word is validate.
178
+ #
179
+ # @param [#to_s] word
180
+ # The word in question.
181
+ #
182
+ # @return [Boolean]
183
+ # Specifies whether the word is valid.
184
+ #
185
+ def check?(word)
186
+ Hunspell.Hunspell_spell(self,word.to_s) != 0
187
+ end
188
+
189
+ alias valid? check?
190
+
191
+ #
192
+ # Finds the stems of a word.
193
+ #
194
+ # @param [#to_s] word
195
+ # The word in question.
196
+ #
197
+ # @return [Array<String>]
198
+ # The stems of the word.
199
+ #
200
+ def stem(word)
201
+ stems = []
202
+
203
+ FFI::MemoryPointer.new(:pointer) do |output|
204
+ count = Hunspell.Hunspell_stem(self,output,word.to_s)
205
+ ptr = output.get_pointer(0)
206
+
207
+ if count > 0
208
+ stems = ptr.get_array_of_string(0,count)
209
+ end
210
+ end
211
+
212
+ return stems.map { |word| force_encoding(word) }
213
+ end
214
+
215
+ #
216
+ # Suggests alternate spellings of a word.
217
+ #
218
+ # @param [#to_s] word
219
+ # The word in question.
220
+ #
221
+ # @return [Array<String>]
222
+ # The suggestions for the word.
223
+ #
224
+ def suggest(word)
225
+ suggestions = []
226
+
227
+ FFI::MemoryPointer.new(:pointer) do |output|
228
+ count = Hunspell.Hunspell_suggest(self,output,word.to_s)
229
+ ptr = output.get_pointer(0)
230
+
231
+ if count > 0
232
+ suggestions = ptr.get_array_of_string(0,count)
233
+ end
234
+ end
235
+
236
+ return suggestions.map { |word| force_encoding(word) }
237
+ end
238
+
239
+ #
240
+ # Closes the dictionary.
241
+ #
242
+ # @return [nil]
243
+ #
244
+ def close
245
+ Hunspell.Hunspell_destroy(self)
246
+
247
+ @ptr = nil
248
+ return nil
249
+ end
250
+
251
+ #
252
+ # Converts the dictionary to a pointer.
253
+ #
254
+ # @return [FFI::Pointer]
255
+ # The pointer for the dictionary.
256
+ #
257
+ def to_ptr
258
+ @ptr
259
+ end
260
+
261
+ protected
262
+
263
+ #
264
+ # Encodes a String into the dictionary's encoding.
265
+ #
266
+ # @param [String] string
267
+ # The unencoded String.
268
+ #
269
+ # @return [String]
270
+ # The encoded String.
271
+ #
272
+ def force_encoding(string)
273
+ string.force_encoding(encoding)
274
+ end
275
+
276
+ end
277
+ end
278
+ end
@@ -0,0 +1,140 @@
1
+ require 'ffi'
2
+
3
+ module FFI
4
+ module Hunspell
5
+ extend FFI::Library
6
+
7
+ ffi_lib [
8
+ 'hunspell-1.7', 'libhunspell-1.7.so.0',
9
+ 'hunspell-1.6', 'libhunspell-1.6.so.0',
10
+ 'hunspell-1.5', 'libhunspell-1.5.so.0',
11
+ 'hunspell-1.4', 'libhunspell-1.4.so.0',
12
+ 'hunspell-1.3', 'libhunspell-1.3.so.0',
13
+ 'hunspell-1.2', 'libhunspell-1.2.so.0'
14
+ ]
15
+
16
+
17
+ attach_function :Hunspell_create, [:string, :string], :pointer
18
+ attach_function :Hunspell_create_key, [:string, :string, :string], :pointer
19
+ attach_function :Hunspell_destroy, [:pointer], :void
20
+ attach_function :Hunspell_spell, [:pointer, :string], :int
21
+ attach_function :Hunspell_get_dic_encoding, [:pointer], :string
22
+ attach_function :Hunspell_suggest, [:pointer, :pointer, :string], :int
23
+ attach_function :Hunspell_analyze, [:pointer, :pointer, :string], :int
24
+ attach_function :Hunspell_stem, [:pointer, :pointer, :string], :int
25
+ attach_function :Hunspell_generate, [:pointer, :pointer, :string, :string], :int
26
+ attach_function :Hunspell_add, [:pointer, :string], :int
27
+ attach_function :Hunspell_add_with_affix, [:pointer, :string, :string], :int
28
+ attach_function :Hunspell_remove, [:pointer, :string], :int
29
+ attach_function :Hunspell_free_list, [:pointer, :pointer, :int], :void
30
+
31
+ begin
32
+ attach_function :Hunspell_add_dic, [:pointer, :string], :int
33
+ rescue FFI::NotFoundError
34
+ define_singleton_method :method_missing do |symbol, *arguments, &block|
35
+ if symbol == :Hunspell_add_dic
36
+ raise NotImplementedError,
37
+ "Hunspell_add_dic was not found in [#{ffi_libraries.map(&:name).join(", ")}]. You must install Hunspell 1.3.4 or later if you need this functionality."
38
+ end
39
+
40
+ super
41
+ end
42
+ end
43
+
44
+ #
45
+ # missing functions:
46
+ #
47
+ # attach_function :Hunspell_stem2, [:pointer, :pointer, :pointer, :int], :int
48
+ # attach_function :Hunspell_generate2, [:pointer, :pointer, :string, :pointer, :int], :int
49
+ #
50
+
51
+ # The language to default to, if no 'LANG' env variable was set.
52
+ DEFAULT_LANG = ENV.fetch('LANG','en_US.UTF-8').split('.',2).first
53
+
54
+ #
55
+ # The default language.
56
+ #
57
+ # @return [String]
58
+ # The name of the default language.
59
+ #
60
+ # @since 0.2.0
61
+ #
62
+ def self.lang
63
+ @lang ||= DEFAULT_LANG
64
+ end
65
+
66
+ #
67
+ # Sets the default language.
68
+ #
69
+ # @param [String] new_lang
70
+ # The new language name.
71
+ #
72
+ # @return [String]
73
+ # The name of the new default language.
74
+ #
75
+ # @since 0.2.0
76
+ #
77
+ def self.lang=(new_lang)
78
+ @lang = new_lang.to_s
79
+ end
80
+
81
+ # The directory name used to store user installed dictionaries.
82
+ USER_DIR = '.hunspell_default'
83
+
84
+ # Known directories to search within for dictionaries.
85
+ KNOWN_DIRECTORIES = [
86
+ # User
87
+ File.join(Gem.user_home,USER_DIR),
88
+ # OS X brew-instlled hunspell
89
+ File.join(Gem.user_home,'Library/Spelling'),
90
+ '/Library/Spelling',
91
+ # Debian
92
+ '/usr/local/share/myspell/dicts',
93
+ '/usr/share/myspell/dicts',
94
+ # Ubuntu
95
+ '/usr/share/hunspell',
96
+ # Fedora
97
+ '/usr/local/share/myspell',
98
+ '/usr/share/myspell',
99
+ # Mac Ports
100
+ '/opt/local/share/hunspell',
101
+ '/opt/share/hunspell'
102
+ ]
103
+
104
+ #
105
+ # The dictionary directories to search for dictionary files.
106
+ #
107
+ # @return [Array<String, Pathname>]
108
+ # The directory paths.
109
+ #
110
+ # @since 0.2.0
111
+ #
112
+ def self.directories
113
+ @directories ||= KNOWN_DIRECTORIES.select do |path|
114
+ File.directory?(path)
115
+ end
116
+ end
117
+
118
+ def self.directories=(dirs)
119
+ @directories = dirs
120
+ end
121
+
122
+ #
123
+ # Opens a Hunspell dictionary.
124
+ #
125
+ # @param [Symbol, String] name
126
+ # The name of the dictionary to open.
127
+ #
128
+ # @yield [dict]
129
+ # The given block will be passed the Hunspell dictionary.
130
+ #
131
+ # @yieldparam [Dictionary] dict
132
+ # The opened dictionary.
133
+ #
134
+ # @return [nil]
135
+ #
136
+ def self.dict(name=Hunspell.lang,&block)
137
+ Dictionary.open(name,&block)
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,142 @@
1
+ require 'spec_helper'
2
+ require 'ffi/hunspell/dictionary'
3
+
4
+ describe Hunspell::Dictionary do
5
+ subject { described_class }
6
+
7
+ let(:lang) { 'en_US' }
8
+ let(:affix_path) { File.join(Hunspell.directories.last,"#{lang}.aff") }
9
+ let(:dic_path) { File.join(Hunspell.directories.last,"#{lang}.dic") }
10
+
11
+ describe "#initialize" do
12
+ subject { described_class.new(affix_path,dic_path) }
13
+
14
+ it "should create a dictionary from '.aff' and '.dic' files" do
15
+ expect(subject.to_ptr).to_not be_nil
16
+ end
17
+
18
+ after { subject.close }
19
+ end
20
+
21
+ describe ".open" do
22
+ subject { described_class }
23
+
24
+ it "should find and open a dictionary file for a given language" do
25
+ subject.open(lang) do |dict|
26
+ expect(dict).to_not be_nil
27
+ end
28
+ end
29
+
30
+ it "should close the dictionary" do
31
+ dict = subject.open(lang)
32
+ dict.close
33
+
34
+ expect(dict).to be_closed
35
+ end
36
+
37
+ context "when given an unknown dictionary name" do
38
+ it "should raise an ArgumentError" do
39
+ expect {
40
+ subject.open('foo')
41
+ }.to raise_error(ArgumentError)
42
+ end
43
+ end
44
+ end
45
+
46
+ context "when opened" do
47
+ subject { described_class.new(affix_path,dic_path) }
48
+
49
+ after { subject.close }
50
+
51
+ it "should provide the encoding of the dictionary files" do
52
+ expect(subject.encoding).to be_instance_of Encoding
53
+ end
54
+
55
+ it "should check if a word is valid" do
56
+ expect(subject.valid?('dog')).to be true
57
+ expect(subject.valid?('dxg')).to be false
58
+ end
59
+
60
+ describe "#add" do
61
+ it "should add a word" do
62
+ expect(subject.add('cat')).to be 0
63
+ end
64
+ end
65
+
66
+ describe "#add_with_affix" do
67
+ it "should add a word with an example word" do
68
+ expect(subject.add_with_affix('cat', 'agree')).to be 0
69
+ expect(subject.valid?('disagreeable')).to be true
70
+ expect(subject.valid?('discatable')).to be true
71
+ end
72
+ end
73
+
74
+ describe "#add_dic" do
75
+ if FFI::Hunspell.respond_to?(:Hunspell_add_dic)
76
+ context "when libhunspell supports add_dic" do
77
+ before { subject.add_dic(File.join(File.dirname(File.realpath(__FILE__)), 'files/extra.dic')) }
78
+
79
+ it "should add an extra dictionary" do
80
+ expect(subject.add_dic(File.join(File.dirname(File.realpath(__FILE__)), 'files/extra.dic'))).to be 0
81
+ end
82
+
83
+ it "should validate a word from the extra dictionary" do
84
+ expect(subject.valid?('dxg')).to be true
85
+ end
86
+
87
+ it "should validate an affixed word based on an affix flag from base affix file" do
88
+ expect(subject.valid?('dxgs')).to be true
89
+ end
90
+ end
91
+ else
92
+ context "when libhunspell does not support add_dic" do
93
+ it "should raise an error" do
94
+ expect { subject.add_dic(File.join(File.dirname(File.realpath(__FILE__)), 'files/extra.dic')) }.to raise_error(NotImplementedError)
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ describe "#stem" do
101
+ it "should find the stems of a word" do
102
+ expect(subject.stem('fishing')).to be == %w[fishing fish]
103
+ end
104
+
105
+ it "should force_encode all strings" do
106
+ expect(subject.suggest('fishing')).to all satisfy { |string|
107
+ string.encoding == subject.encoding
108
+ }
109
+ end
110
+
111
+ context "when there are no stems" do
112
+ it "should return []" do
113
+ expect(subject.stem("zzzzzzz")).to be == []
114
+ end
115
+ end
116
+ end
117
+
118
+ describe "#suggest" do
119
+ it "should suggest alternate spellings for words" do
120
+ expect(subject.suggest('arbitrage')).to include(
121
+ 'arbitrage',
122
+ 'arbitrages',
123
+ 'arbitrager',
124
+ 'arbitraged',
125
+ 'arbitrate'
126
+ )
127
+ end
128
+
129
+ it "should force_encode all strings" do
130
+ expect(subject.suggest('arbitrage')).to all satisfy { |string|
131
+ string.encoding == subject.encoding
132
+ }
133
+ end
134
+
135
+ context "when there are no suggestions" do
136
+ it "should return []" do
137
+ expect(subject.suggest("________")).to be == []
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,2 @@
1
+ 1
2
+ dxg/MS
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+ require 'ffi/hunspell/hunspell'
3
+
4
+ describe Hunspell do
5
+ describe ".lang" do
6
+ subject { super().lang }
7
+
8
+ it "should have a default language" do
9
+ expect(subject).to_not be_nil
10
+ expect(subject).to_not be_empty
11
+ end
12
+ end
13
+
14
+ describe ".directories" do
15
+ subject { super().directories }
16
+
17
+ it "should have directories to search within" do
18
+ expect(subject).to_not be_empty
19
+ end
20
+ end
21
+
22
+ describe ".dict" do
23
+ it "should open a dictionary file" do
24
+ subject.dict('en_US') do |dict|
25
+ expect(dict).to_not be_nil
26
+ end
27
+ end
28
+
29
+ it "should open the dictionary file for the default language" do
30
+ subject.dict do |dict|
31
+ expect(dict).to_not be_nil
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,12 @@
1
+ require 'rspec'
2
+ require 'ffi/hunspell'
3
+
4
+ include FFI
5
+
6
+ RSpec.configure do |specs|
7
+ specs.before(:suite) do
8
+ if ENV['HUNSPELL_ROOT']
9
+ Hunspell.directories << ENV['HUNSPELL_ROOT']
10
+ end
11
+ end
12
+ end
metadata ADDED
@@ -0,0 +1,123 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ffi-hunspell-wtchappell
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ platform: ruby
6
+ authors:
7
+ - Postmodern
8
+ - cdchapman
9
+ - wtchappell
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2019-04-28 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ffi
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - "~>"
20
+ - !ruby/object:Gem::Version
21
+ version: '1.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - "~>"
27
+ - !ruby/object:Gem::Version
28
+ version: '1.0'
29
+ - !ruby/object:Gem::Dependency
30
+ name: rubygems-tasks
31
+ requirement: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - "~>"
34
+ - !ruby/object:Gem::Version
35
+ version: '0.1'
36
+ type: :development
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - "~>"
41
+ - !ruby/object:Gem::Version
42
+ version: '0.1'
43
+ - !ruby/object:Gem::Dependency
44
+ name: rspec
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '3.0'
50
+ type: :development
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '3.0'
57
+ - !ruby/object:Gem::Dependency
58
+ name: yard
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: '0.7'
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - "~>"
69
+ - !ruby/object:Gem::Version
70
+ version: '0.7'
71
+ description: Ruby FFI bindings for the Hunspell spell checker and multi-dictionary
72
+ support.
73
+ email: wtchappell@gmail.com
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files:
77
+ - ChangeLog.md
78
+ - LICENSE.txt
79
+ - README.md
80
+ files:
81
+ - ".gemtest"
82
+ - ".gitignore"
83
+ - ".rspec"
84
+ - ".travis.yml"
85
+ - ".yardopts"
86
+ - ChangeLog.md
87
+ - LICENSE.txt
88
+ - README.md
89
+ - Rakefile
90
+ - ffi-hunspell.gemspec
91
+ - gemspec.yml
92
+ - lib/ffi/hunspell.rb
93
+ - lib/ffi/hunspell/dictionary.rb
94
+ - lib/ffi/hunspell/hunspell.rb
95
+ - spec/dictionary_spec.rb
96
+ - spec/files/extra.dic
97
+ - spec/hunspell_spec.rb
98
+ - spec/spec_helper.rb
99
+ homepage: https://github.com/wtchappell/ffi-hunspell
100
+ licenses:
101
+ - MIT
102
+ metadata: {}
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: 1.9.1
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements:
118
+ - libhunspell >= 1.2.0
119
+ rubygems_version: 3.0.1
120
+ signing_key:
121
+ specification_version: 4
122
+ summary: FFI bindings for Hunspell
123
+ test_files: []