thinking-sphinx-raspell 1.0.0 → 1.1.0

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.
@@ -38,13 +38,28 @@ You can also choose to redo the search using the provided suggestion:
38
38
  # ...
39
39
  end</code></pre>
40
40
 
41
+ h2. Configuration
42
+
43
+ You can customise the following settings - either in your @config/environment.rb@ file, or perhaps in an initializer. Example syntax below highlights the current defaults.
44
+
45
+ <pre><code>config = ThinkingSphinx::Configuration.instance
46
+ config.raspell.dictionary = 'en'
47
+ config.raspell.suggestion_mode = :normal
48
+ config.raspell.options['ignore-case'] = true</code></pre>
49
+
50
+ You can look at the available options using the following two collections:
51
+
52
+ <pre><code>config = ThinkingSphinx::Configuration.instance
53
+ config.raspell.dictionaries #=> ['en', 'en_GB', 'en_US', ... ]
54
+ config.raspell.suggestion_modes #=> [:ultra, :fast, :normal, :badspellers]</code></pre>
55
+
56
+ If you need more documentation, you can check out the YARD files "on rdoc.info":http://rdoc.info/projects/freelancing-god/thinking-sphinx-raspell. This isn't a big library, though - what you see in this readme is pretty much what you get.
57
+
41
58
  h2. Limitations
42
59
 
43
- * Currently only uses (and thus requires) the en_US dictionary.
44
- * Spelling suggestions are done via Raspell's normal mode, and are case insensitive.
45
60
  * Only checks normal query strings, not field-specific queries via the @:conditions@ hash.
46
61
 
47
- Patches are very much welcome - I would like to address all of the above limitations.
62
+ Patches are very much welcome - I would like to address this last remaining limitation.
48
63
 
49
64
  h2. Copyright
50
65
 
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 1
3
- :minor: 0
3
+ :minor: 1
4
4
  :patch: 0
@@ -1,4 +1,5 @@
1
1
  require 'raspell'
2
+ require 'thinking_sphinx/raspell/configuration'
2
3
 
3
4
  module ThinkingSphinx
4
5
  # Module for adding suggestion support into Thinking Sphinx. This gets
@@ -56,19 +57,12 @@ module ThinkingSphinx
56
57
  speller.check(word) ? word : speller.suggest(word).first
57
58
  end
58
59
 
59
- # Aspell instance with all appropriate settings defined (dictionary set to
60
- # en_US, suggestion mode set to Aspell::NORMAL, and ignore-case set to
61
- # true).
60
+ # Aspell instance with all appropriate settings defined.
62
61
  #
63
62
  # @return [Aspell] the prepared Aspell instance
64
63
  #
65
64
  def speller
66
- @speller ||= begin
67
- speller = Aspell.new('en_US')
68
- speller.suggestion_mode = Aspell::NORMAL
69
- speller.set_option "ignore-case", "true"
70
- speller
71
- end
65
+ ThinkingSphinx::Configuration.instance.raspell.speller
72
66
  end
73
67
  end
74
68
  end
@@ -0,0 +1,142 @@
1
+ module ThinkingSphinx
2
+ module Raspell
3
+ # Configuration settings for spelling suggestions in Thinking Sphinx. You
4
+ # can access these either by the singleton instance
5
+ # (ThinkingSphinx::Raspell::Configuration.instance), or through Thinking
6
+ # Sphinx's existing configuration instance
7
+ # (ThinkingSphinx::Configuration.instance.raspell).
8
+ #
9
+ # @author Pat Allan
10
+ #
11
+ class Configuration
12
+ include Singleton
13
+
14
+ attr_reader :dictionary, :suggestion_mode, :options
15
+
16
+ # Creates the instance of the singleton with the following defaults:
17
+ # Dictionary is English (en), suggestion mode is normal, and the
18
+ # ignore-case option is enabled.
19
+ #
20
+ def initialize
21
+ reset
22
+ end
23
+
24
+ # Resets the instance to the default settings. Probably not necessary in
25
+ # general usage, but makes specs easier to run.
26
+ #
27
+ def reset
28
+ @dictionary = 'en'
29
+ @suggestion_mode = :normal
30
+ @options = {'ignore-case' => true}
31
+ @speller = nil
32
+ end
33
+
34
+ # Sets the dictionary for the spelling suggestions. Make sure you have the
35
+ # dictionary installed on your system first.
36
+ #
37
+ # @example
38
+ # config.dictionary = 'en_GB'
39
+ #
40
+ # @param [String] dict dictionary code
41
+ # @raise [ArgumentError] if the dictionary code is not known by Aspell
42
+ #
43
+ def dictionary=(dict)
44
+ unless dictionaries.include?(dict)
45
+ raise ArgumentError, 'unknown dictionary'
46
+ end
47
+
48
+ @dictionary = dict
49
+ end
50
+
51
+ # The list of dictionaries Aspell has on offer.
52
+ #
53
+ # @return [Array] collection of dictionary codes
54
+ #
55
+ def dictionaries
56
+ @dictionaries ||= Aspell.list_dicts.collect { |dict| dict.code }
57
+ end
58
+
59
+ # Set the suggestion mode. Accepts symbols, strings and Aspell constants.
60
+ # The known values are ultra, fast, normal and badspellers/bad-spellers.
61
+ #
62
+ # @param [Symbol, String] mode suggestion mode
63
+ # @raise [ArgumentError] if the suggestion mode is not known by Aspell
64
+ #
65
+ def suggestion_mode=(mode)
66
+ mode = mode.gsub(/-/, '').to_sym if mode.is_a?(String)
67
+
68
+ unless suggestion_modes.include?(mode)
69
+ raise ArgumentError, 'unknown suggestion mode'
70
+ end
71
+
72
+ @suggestion_mode = mode
73
+ end
74
+
75
+ # The allowed suggestion modes.
76
+ #
77
+ # @return [Array] available suggestion modes, as symbols.
78
+ #
79
+ def suggestion_modes
80
+ [:ultra, :fast, :normal, :badspellers]
81
+ end
82
+
83
+ # Aspell instance with all appropriate settings defined.
84
+ #
85
+ # @return [Aspell] the prepared Aspell instance
86
+ #
87
+ def speller
88
+ @speller ||= build_speller
89
+ end
90
+
91
+ private
92
+
93
+ # Convert the suggestion mode symbol to a string, and ensures the dash
94
+ # is added to the bad-spellers mode.
95
+ #
96
+ # @return [String] Aspell-friendly suggestion mode
97
+ #
98
+ def actual_suggestion_mode
99
+ suggestion_mode.to_s.gsub(/badspellers/, 'bad-spellers')
100
+ end
101
+
102
+ # Converts user-defined options to have string keys, as that's what Aspell
103
+ # requires.
104
+ #
105
+ # @return [Hash] options with string keys
106
+ #
107
+ def actual_options
108
+ options.keys.inject({}) do |hash, key|
109
+ hash[key] = options[key].to_s
110
+ hash
111
+ end
112
+ end
113
+
114
+ # Generate the Aspell instance, setting the dictionary, suggestion mode
115
+ # and options as defined in the configuration instance.
116
+ #
117
+ # @return [Aspell] a new prepared Aspell instance
118
+ #
119
+ def build_speller
120
+ speller = Aspell.new(dictionary)
121
+ speller.suggestion_mode = actual_suggestion_mode
122
+ actual_options.each do |key, value|
123
+ speller.set_option key, value
124
+ end
125
+
126
+ speller
127
+ end
128
+ end
129
+
130
+ module Hooks
131
+ # The singleton ThinkingSphinx::Raspell::Configuration instance.
132
+ #
133
+ # @return [ThinkingSphinx::Raspell::Configuration] config instance
134
+ #
135
+ def raspell
136
+ ThinkingSphinx::Raspell::Configuration.instance
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ ThinkingSphinx::Configuration.send(:include, ThinkingSphinx::Raspell::Hooks)
@@ -0,0 +1,122 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ThinkingSphinx::Configuration do
4
+ describe '#raspell' do
5
+ before :each do
6
+ @config = ThinkingSphinx::Configuration.instance
7
+ end
8
+
9
+ it "should return a raspell configuration instance" do
10
+ @config.raspell.should be_a(ThinkingSphinx::Raspell::Configuration)
11
+ end
12
+ end
13
+ end
14
+
15
+ describe ThinkingSphinx::Raspell::Configuration do
16
+ before :each do
17
+ @config = ThinkingSphinx::Raspell::Configuration.instance
18
+ @config.reset
19
+ end
20
+
21
+ describe '#dictionary' do
22
+ it "should default to 'en'" do
23
+ @config.dictionary.should == 'en'
24
+ end
25
+ end
26
+
27
+ describe '#dictionary=' do
28
+ it "should set the dictionary" do
29
+ @config.dictionary = 'en_GB'
30
+ @config.dictionary.should == 'en_GB'
31
+ end
32
+
33
+ it "should raise an argument error if the dictionary code is invalid" do
34
+ lambda { @config.dictionary = 'zz' }.should raise_error(ArgumentError)
35
+ end
36
+ end
37
+
38
+ describe '#dictionaries' do
39
+ it "should return the names of all registered dictionaries" do
40
+ @config.dictionaries.should == Aspell.list_dicts.collect { |dict|
41
+ dict.code
42
+ }
43
+ end
44
+ end
45
+
46
+ describe '#suggestion_mode' do
47
+ it "should default to normal" do
48
+ @config.suggestion_mode.should == :normal
49
+ end
50
+ end
51
+
52
+ describe '#suggestion_mode=' do
53
+ it "should set the suggestion mode" do
54
+ @config.suggestion_mode = :ultra
55
+ @config.suggestion_mode.should == :ultra
56
+ end
57
+
58
+ it "should raise an argument error if the suggestion mode is invalid" do
59
+ lambda { @config.suggestion_mode = :smart }.
60
+ should raise_error(ArgumentError)
61
+ end
62
+
63
+ it "should translate Aspell constants" do
64
+ @config.suggestion_mode = Aspell::BADSPELLERS
65
+ @config.suggestion_mode.should == :badspellers
66
+ end
67
+ end
68
+
69
+ describe '#options' do
70
+ it "should return a Hash" do
71
+ @config.options.should be_a(Hash)
72
+ end
73
+
74
+ it "should have ignore-case defaulting to true" do
75
+ @config.options['ignore-case'].should == true
76
+ end
77
+ end
78
+
79
+ describe '#suggestion_modes' do
80
+ it "should return ultra, fast, normal and badspellers" do
81
+ @config.suggestion_modes.should == [:ultra, :fast, :normal, :badspellers]
82
+ end
83
+ end
84
+
85
+ describe '#speller' do
86
+ it "should return an Aspell instance" do
87
+ @config.speller.should be_an(Aspell)
88
+ end
89
+
90
+ it "should use the configured dictionary" do
91
+ speller = Aspell.new('en_GB')
92
+ Aspell.should_receive(:new).with('en_GB').and_return(speller)
93
+
94
+ @config.dictionary = 'en_GB'
95
+ @config.speller
96
+ end
97
+
98
+ it "should set the configured suggestion mode" do
99
+ speller = Aspell.new('en')
100
+ speller.should_receive(:suggestion_mode=).with('bad-spellers')
101
+ Aspell.stub!(:new => speller)
102
+
103
+ @config.suggestion_mode = :badspellers
104
+ @config.speller
105
+ end
106
+
107
+ it "should set the configured options" do
108
+ @config.options['ignore-case'] = false
109
+
110
+ @config.speller.get_option('ignore-case').should == 'false'
111
+ end
112
+
113
+ it "should reuse the generated instance" do
114
+ Aspell.should_receive(:new).once.and_return(
115
+ stub('speller').as_null_object
116
+ )
117
+
118
+ @config.speller
119
+ @config.speller
120
+ end
121
+ end
122
+ end
@@ -1,6 +1,10 @@
1
1
  require 'spec/spec_helper'
2
2
 
3
3
  describe ThinkingSphinx::Search do
4
+ before :each do
5
+ ThinkingSphinx::Configuration.instance.raspell.reset
6
+ end
7
+
4
8
  describe '#suggestion' do
5
9
  it "should return a spelling suggestion, if there is one" do
6
10
  search = ThinkingSphinx::Search.new('wodrs incorret on purpose')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thinking-sphinx-raspell
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pat Allan
@@ -66,6 +66,7 @@ files:
66
66
  - README.textile
67
67
  - VERSION.yml
68
68
  - lib/thinking_sphinx/raspell.rb
69
+ - lib/thinking_sphinx/raspell/configuration.rb
69
70
  has_rdoc: true
70
71
  homepage: http://ts.freelancing-gods.com
71
72
  licenses: []
@@ -96,4 +97,5 @@ specification_version: 3
96
97
  summary: An add-on gem for spelling suggestions in Thinking Sphinx
97
98
  test_files:
98
99
  - spec/spec_helper.rb
100
+ - spec/thinking_sphinx/raspell/configuration_spec.rb
99
101
  - spec/thinking_sphinx/raspell_spec.rb