soulmate_rails 0.2.0.alpha → 0.2.1.beta

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.
@@ -1,17 +1,22 @@
1
- # Soulmate Rails
1
+ # Soulmate Rails [![Gem Version](https://badge.fury.io/rb/soulmate_rails.png)](http://badge.fury.io/rb/soulmate_rails) [![Build Status](https://travis-ci.org/dhruvasagar/soulmate_rails.png?branch=master)](https://travis-ci.org/dhruvasagar/soulmate_rails) [![Dependency Status](https://gemnasium.com/dhruvasagar/soulmate_rails.png)](https://gemnasium.com/dhruvasagar/soulmate_rails)
2
+ <!--[![Build Status](https://drone.io/github.com/dhruvasagar/soulmate_rails/status.png)](https://drone.io/github.com/dhruvasagar/soulmate_rails/latest)-->
2
3
 
3
- Soulmate Rails is a rails plugin that helps to solve the common problem of
4
- auto-completion in rails intuitively. It extends the soulmate gem <a
5
- href="http://github.com/seatgeek/soulmate">Soulmate</a> to make it easily
6
- pluggable into a rails project.
4
+ Soulmate Rails is a rails plugin that helps to solve the common problem
5
+ building auto-completion back-end in rails intuitively. It extends the
6
+ soulmate gem <a href="http://github.com/seatgeek/soulmate">Soulmate</a> to
7
+ make it easily pluggable into a rails project.
7
8
 
8
9
  ## Getting Started
9
-
10
10
  ### Installation :
11
11
 
12
12
  ```sh
13
13
  $ gem install soulmate_rails
14
14
  ```
15
+ OR add this to your `Gemfile` :
16
+
17
+ ```ruby
18
+ gem 'soulmate_rails'
19
+ ```
15
20
 
16
21
  ### Usage :
17
22
 
@@ -24,7 +29,7 @@ class User < ActiveRecord::Base
24
29
  autocomplete :last_name, :score => :id
25
30
 
26
31
  def calculate_score
27
- # Some magic calculation returning a number.
32
+ 100 / self.id # simple score calculator
28
33
  end
29
34
  end
30
35
 
@@ -33,15 +38,23 @@ end
33
38
  1.9.3p385 :003 > User.create(:first_name => 'First3', :last_name => 'Last3')
34
39
  1.9.3p385 :004 > User.search_by_first_name('firs')
35
40
  => [#<User:0x000000014bb1e8 @new_record=false,
36
- @attributes={"first_name"=>"First3", "last_name"=>"Last3" "id"=>3},
41
+ @attributes={"first_name"=>"First1", "last_name"=>"Last1" "id"=>1},
37
42
  @changed_attributes={}>, #<User:0x000000014bb1e9 @new_record=false,
38
43
  @attributes={"first_name"=>"First2", "last_name"=>"Last2" "id"=>2},
39
44
  @changed_attributes={}>, #<User:0x000000014bb1ea @new_record=false,
40
- @attributes={"first_name"=>"First1", "last_name"=>"Last1" "id"=>1},
45
+ @attributes={"first_name"=>"First3", "last_name"=>"Last3" "id"=>3},
41
46
  @changed_attributes={}>]
42
47
  1.9.3p385 :005 > User.search_by_last_name('last1')
48
+ => [#<User:0x000000014bb1e8 @new_record=false,
49
+ @attributes={"first_name"=>"First1", "last_name"=>"Last1" "id"=>1},
50
+ @changed_attributes={}>]
51
+ 1.9.3p385 :006 > User.search_by_last_name('las')
43
52
  => [#<User:0x000000014bb1e8 @new_record=false,
44
53
  @attributes={"first_name"=>"First3", "last_name"=>"Last3" "id"=>3},
54
+ @changed_attributes={}>, #<User:0x000000014bb1e9 @new_record=false,
55
+ @attributes={"first_name"=>"First2", "last_name"=>"Last2" "id"=>2},
56
+ @changed_attributes={}>, #<User:0x000000014bb1ea @new_record=false,
57
+ @attributes={"first_name"=>"First1", "last_name"=>"Last1" "id"=>1},
45
58
  @changed_attributes={}>]
46
59
  ```
47
60
 
@@ -50,8 +63,7 @@ The `autocomplete` method takes 2 arguments :
50
63
  * attribute name to use for autocompletion.
51
64
  * options that determine how autocompletion works for indexing.
52
65
 
53
- Methods added by autocomplete :
54
-
66
+ ### Methods added by autocomplete :
55
67
  * Class Methods
56
68
  * `search_by(attribute, term, options={})` - Generic method to search by
57
69
  an attribute for which an autocomplete was defined.
@@ -67,14 +79,36 @@ Methods added by autocomplete :
67
79
  `delete` to ensure the callbacks are invoked appropriately by rails and
68
80
  soulmate updates the index.
69
81
 
70
- Options you can provide to `autocomplete` :
82
+ ### Options you can provide to `autocomplete` :
83
+ * `:score` : This is required. Soulmate uses it for sorting the results (in
84
+ reverse order, i.e. higher score first). This can be the name of a function
85
+ or can also be the name of another attribute with integer values.
86
+ * `:aliases` : This is optional. Soulmate uses this as aliases for the term
87
+ field and uses it for searching as well. This can be an array of values or
88
+ the name of a method which returns an array of values.
89
+ * `:data` : This is optional. This can either be the name of a method which
90
+ returns data or a hash or a string. Once you perform your search using
91
+ `search_by` or `search_by_#{attribute}` it will set the value of :data
92
+ corresponding to the object to soulmate_data attr_accessor and can be
93
+ accessed by calling the soulmate_data accessor on the model object.
94
+
95
+ ### Configuration :
96
+ Within your rails application inside config/application.rb you can optionally
97
+ provide redis configuration. Example :
71
98
 
72
- * `:score` : This is required. Soulmate uses it for sorting the results (in
73
- reverse order, i.e. higher score first). This can be the name of a function
74
- or can also be the name of another attribute with integer values.
75
- * `:aliases` : This is optional. Soulmate uses this as aliases for the term
76
- field and uses it for searching as well. This can be an array of values or
77
- a method name which returns an array of values.
99
+ ```ruby
100
+ config.soulmate_rails.redis = 'redis://127.0.0.1:6380/0'
101
+ # or you can assign an existing instance of Redis, Redis::Namespace, etc.
102
+ # config.soulmate_rails.redis = $redis
103
+ ```
104
+
105
+ Alternatively, you can also add configuration in an initializer. Example :
106
+
107
+ ```ruby
108
+ Soulmate.redis = 'redis://127.0.0.1:6380/0'
109
+ # or you can assign an existing instance of Redis, Redis::Namespace, etc.
110
+ # Soulmate.redis = $redis
111
+ ```
78
112
 
79
113
  ## Contributing
80
114
  ### Reporting an Issue :
@@ -88,6 +122,7 @@ Options you can provide to `autocomplete` :
88
122
  * Open a Pull Request.
89
123
 
90
124
  ## License
91
- Soulmate Rails is released under the MIT License
125
+ Soulmate Rails is released under the <a
126
+ href="http://www.opensource.org/licenses/MIT">MIT License</a>
92
127
 
93
128
  <!-- vim: set tw=80 colorcolumn=80 -->
@@ -2,15 +2,39 @@ module SoulmateRails
2
2
  module ModelAdditions
3
3
  extend ActiveSupport::Concern
4
4
 
5
+ included do
6
+ class_eval do
7
+ attr_accessor :soulmate_data
8
+ end
9
+ end
10
+
5
11
  def update_index_for(attribute, options={})
6
12
  loader = instance_variable_get("@#{loader_for(attribute)}") || instance_variable_set("@#{loader_for(attribute)}", Soulmate::Loader.new(loader_for(attribute)))
7
13
  item = {
8
14
  'id' => "#{attribute}_#{self.id}",
9
15
  'term' => send(attribute),
10
16
  'score' => ( respond_to?(options[:score]) ? send(options[:score]) : options[:score] )
11
- }.merge( options[:aliases] ? ( respond_to?(options[:aliases]) ? send(options[:aliases]) : options[:aliases] ) : {} )
12
- # NOTE: Not supporting :data for now, will find a better way to use this later.
13
- # .merge( options[:data] ? ( respond_to?(options[:data]) ? send(options[:data]) : options[:data] ) : {} )
17
+ }
18
+
19
+ if options[:aliases]
20
+ if options[:aliases].is_a?(Array)
21
+ item.merge!({'aliases' => options[:aliases]})
22
+ elsif respond_to?(options[:aliases])
23
+ aliases = send(options[:aliases])
24
+ item.merge!({'aliases' => aliases}) if aliases && aliases.is_a?(Array)
25
+ end
26
+ end
27
+
28
+ if options[:data]
29
+ if options[:data].is_a?(Hash)
30
+ item.merge!({'data' => options[:data]})
31
+ elsif respond_to?(options[:data])
32
+ item.merge!({'data' => send(options[:data])})
33
+ elsif options[:data].is_a?(String)
34
+ item.merge!({'data' => options[:data]})
35
+ end
36
+ end
37
+
14
38
  loader.add(item, options)
15
39
  end
16
40
 
@@ -45,8 +69,10 @@ module SoulmateRails
45
69
  matcher = instance_variable_get("@#{matcher_for(attribute)}") || instance_variable_set("@#{matcher_for(attribute)}", Soulmate::Matcher.new(matcher_for(attribute)))
46
70
  matches = matcher.matches_for_term(term, options)
47
71
  matches = matches.map do |match|
48
- find(match['id'].split('_')[-1].to_i) rescue nil
49
- end.compact
72
+ object = find(match['id'].split('_')[-1].to_i)
73
+ object.soulmate_data = match['data'].symbolize_keys if object && match['data']
74
+ object
75
+ end
50
76
  end
51
77
 
52
78
  def matcher_for(attribute)
@@ -1,8 +1,8 @@
1
1
  module SoulmateRails
2
2
  MAJOR = 0
3
3
  MINOR = 2
4
- PATCH = 0
5
- STATUS = 'alpha'
4
+ PATCH = 1
5
+ STATUS = 'beta'
6
6
 
7
7
  VERSION = [MAJOR, MINOR, PATCH, STATUS].compact.join('.')
8
8
  end
@@ -0,0 +1,9 @@
1
+ class UserAliases < SuperModel::Base
2
+ include SoulmateRails::ModelAdditions
3
+
4
+ autocomplete :name, :score => :id, :aliases => :name_aliases
5
+
6
+ def name_aliases
7
+ self.name.split(' ').map(&:reverse)
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ class UserData < SuperModel::Base
2
+ include SoulmateRails::ModelAdditions
3
+
4
+ autocomplete :name, :score => :id, :data => {:source => 'test'}
5
+ end
@@ -0,0 +1,6 @@
1
+ class UserMultiple < SuperModel::Base
2
+ include SoulmateRails::ModelAdditions
3
+
4
+ autocomplete :name, :score => :id
5
+ autocomplete :country, :score => :id
6
+ end
@@ -0,0 +1,5 @@
1
+ class UserSingle < SuperModel::Base
2
+ include SoulmateRails::ModelAdditions
3
+
4
+ autocomplete :name, :score => :id
5
+ end
@@ -1,45 +1,91 @@
1
1
  require 'spec_helper'
2
2
 
3
- module SoulmateRails
4
- class User < SuperModel::Base
5
- include ModelAdditions
6
-
7
- autocomplete :name, :score => :id
8
- end
3
+ require 'samples/models/user_single'
4
+ require 'samples/models/user_multiple'
5
+ require 'samples/models/user_aliases'
6
+ require 'samples/models/user_data'
9
7
 
8
+ module SoulmateRails
10
9
  describe ModelAdditions do
11
- context 'single autocomplete' do
10
+ context 'autocomplete for name' do
12
11
  before :each do
13
- @user = User.create(:name => 'Dhruva Sagar')
12
+ @user = UserSingle.create(:name => 'Dhruva Sagar')
14
13
  end
15
14
 
16
15
  it 'should successfully search by name' do
17
- users = User.search_by_name('dhruv')
16
+ # By first name
17
+ users = UserSingle.search_by_name('dhr')
18
18
  user = users.first
19
19
  user.should eq(@user)
20
+
21
+ # By last name
22
+ users = UserSingle.search_by_name('sag')
23
+ user = users.first
24
+ user.should eq(@user)
25
+ end
26
+
27
+ after :each do
28
+ UserSingle.destroy_all
20
29
  end
21
30
  end
22
31
 
23
- context 'multiple autocompletes' do
32
+ context 'autocomplete for name and country' do
24
33
  before :each do
25
- # Define another autocomplete for country
26
- User.autocomplete(:country, :score => :id)
27
- @user = User.create(:name => 'Dhruva Sagar', :country => 'India')
34
+ @user = UserMultiple.create(:name => 'Dhruva Sagar', :country => 'India')
28
35
  end
29
36
 
30
37
  it 'should successfully search by name as well as country' do
31
- users = User.search_by_name('dhr')
38
+ users = UserMultiple.search_by_name('dhr')
39
+ user = users.first
40
+ user.should eq(@user)
41
+
42
+ users = UserMultiple.search_by_country('ind')
43
+ user = users.first
44
+ user.should eq(@user)
45
+ end
46
+
47
+ after :each do
48
+ UserMultiple.destroy_all
49
+ end
50
+ end
51
+
52
+ context 'autocomplete name with aliases' do
53
+ before :each do
54
+ @user = UserAliases.create(:name => 'Dhruva Sagar')
55
+ end
56
+
57
+ it 'should successfully search by name' do
58
+ # By reverse of my first name
59
+ users = UserAliases.search_by_name('avu')
32
60
  user = users.first
33
61
  user.should eq(@user)
34
62
 
35
- users = User.search_by_country('ind')
63
+ # By reverse of my last name
64
+ users = UserAliases.search_by_name('rag')
36
65
  user = users.first
37
66
  user.should eq(@user)
38
67
  end
68
+
69
+ after :each do
70
+ UserAliases.destroy_all
71
+ end
39
72
  end
40
73
 
41
- after :each do
42
- User.destroy_all
74
+ context 'autocomplete name with additional data' do
75
+ before :each do
76
+ @user = UserData.create(:name => 'Dhruva Sagar', :country => 'India')
77
+ end
78
+
79
+ it 'should successfully search by name and set data' do
80
+ users = UserData.search_by_name('dhr')
81
+ user = users.first
82
+ user.should eq(@user)
83
+ user.soulmate_data.should eq({:source => 'test'})
84
+ end
85
+
86
+ after :each do
87
+ UserData.destroy_all
88
+ end
43
89
  end
44
90
  end
45
91
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: soulmate_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0.alpha
4
+ version: 0.2.1.beta
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-04 00:00:00.000000000 Z
12
+ date: 2013-03-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis
@@ -132,11 +132,9 @@ executables: []
132
132
  extensions: []
133
133
  extra_rdoc_files: []
134
134
  files:
135
- - .document
136
135
  - .gitignore
137
136
  - .rvmrc
138
137
  - Gemfile
139
- - LICENSE.txt
140
138
  - README.markdown
141
139
  - Rakefile
142
140
  - lib/soulmate/base.rb
@@ -149,6 +147,10 @@ files:
149
147
  - lib/soulmate_rails/version.rb
150
148
  - soulmate_rails.gemspec
151
149
  - spec/config/test.conf
150
+ - spec/samples/models/user_aliases.rb
151
+ - spec/samples/models/user_data.rb
152
+ - spec/samples/models/user_multiple.rb
153
+ - spec/samples/models/user_single.rb
152
154
  - spec/samples/stop-words.txt
153
155
  - spec/samples/venues.json
154
156
  - spec/soulmate/loader_spec.rb
@@ -170,7 +172,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
170
172
  version: '0'
171
173
  segments:
172
174
  - 0
173
- hash: -2339712200945415298
175
+ hash: 270579878346958434
174
176
  required_rubygems_version: !ruby/object:Gem::Requirement
175
177
  none: false
176
178
  requirements:
data/.document DELETED
@@ -1,5 +0,0 @@
1
- lib/**/*.rb
2
- bin/*
3
- -
4
- features/**/*.feature
5
- LICENSE.txt
@@ -1,20 +0,0 @@
1
- Copyright (c) 2011 Eric Waller
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
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.