redis-autosuggest 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Redis::Autosuggest
2
2
 
3
- TODO: Write a gem description
3
+ Provides autocompletions through Redis, with the ability to rank
4
+ results and integrate with Rails
4
5
 
5
6
  ## Installation
6
7
 
@@ -18,7 +19,56 @@ Or install it yourself as:
18
19
 
19
20
  ## Usage
20
21
 
21
- TODO: Write usage instructions here
22
+ By default Autosuggest creates a new Redis client on db 0 at localhost:6379.
23
+
24
+ To change the server/port:
25
+ ```ruby
26
+ r = Redis.new(:host => "my_host", :port => my_port)
27
+ Redis::Autosuggest.redis = r
28
+ ```
29
+
30
+ To add items to be use for autocompletions:
31
+ ```ruby
32
+ Redis::Autosuggest.add("North By Northwest", "Northern Exposure")
33
+ ```
34
+
35
+ To check for autocompletions for an item:
36
+ ```ruby
37
+ Redis::Autosuggest.suggest("nor")
38
+ # => ["north by northwest", "northern exposure"]
39
+ ```
40
+ Autocompletions will be ordered their score value (descending).
41
+
42
+ Some other usage examples:
43
+ ```ruby
44
+ # Add items with initial scores
45
+ Redis::Autosuggest.suggest("North By Northwest", 9, Northern Exposure, 3)
46
+ # Increment an item's score
47
+ Redis::Autosuggest.suggest("North By Northwest", 1)
48
+ ```
49
+
50
+ ## Rails support
51
+
52
+ Autosuggest can also be integrated with Rails. Include it in a model:
53
+ ```ruby
54
+ class Movie < ActiveRecord::Base
55
+ include Redis::Autosuggest
56
+
57
+ attr_accessible :movie_title
58
+ autosuggest :movie_title
59
+ end
60
+ ```
61
+
62
+ For first time usage, seed the Redis db with the autosuggest sources:
63
+ ```ruby
64
+ Redis::Autosuggest.init_rails_sources
65
+ ```
66
+
67
+ You can optionally specify a numeric field to be used as the initial score for an item
68
+ when it is added:
69
+ ```ruby
70
+ autosuggest :movie_title, :rank_by => imdb_rating
71
+ ```
22
72
 
23
73
  ## Contributing
24
74
 
@@ -1,5 +1,11 @@
1
1
  require 'redis'
2
2
  require 'redis-namespace'
3
3
  require 'redis/autosuggest'
4
- require 'redis/autosuggest/version'
5
4
  require 'redis/autosuggest/config'
5
+ require 'redis/autosuggest/file'
6
+ require 'redis/autosuggest/init'
7
+ require 'redis/autosuggest/version'
8
+
9
+ if defined?(Rails)
10
+ require 'redis/autosuggest/rails'
11
+ end
@@ -12,7 +12,7 @@ class Redis
12
12
  add_item(i.downcase)
13
13
  end
14
14
  end
15
-
15
+
16
16
  # Add item(s) along with their scores.
17
17
  # add_with_score("item1", 4, "item2", 1, "item3", 0)
18
18
  def add_with_score(*fields)
@@ -55,6 +55,11 @@ class Redis
55
55
  top_ids.empty? ? [] : @db.hmget(@items, top_ids)
56
56
  end
57
57
 
58
+ # Get the score of an item
59
+ def get_score(item)
60
+ @substrings.zscore(item.downcase, get_id(item.downcase))
61
+ end
62
+
58
63
  private
59
64
  def add_item(item, score=0)
60
65
  id = self.db.hlen(self.items)
@@ -23,15 +23,19 @@ class Redis
23
23
 
24
24
  # Key to a sorted set holding all id of items in the autosuggest database sorted
25
25
  # by their score
26
- @leaderboard = "leaderboard"
26
+ @leaderboard = "lead"
27
27
 
28
28
  # Leaderboard off by default
29
29
  @use_leaderboard = false
30
30
 
31
+ # Sources to be used for Autocomplete in rails.
32
+ # Example: { Movie => :movie_title }
33
+ @rails_sources = {}
34
+
31
35
  class << self
32
36
  attr_reader :redis
33
37
  attr_accessor :db, :items, :substrings, :max_per_substring, :max_results,
34
- :leaderboard, :use_leaderboard
38
+ :leaderboard, :use_leaderboard, :rails_sources
35
39
 
36
40
  def redis=(redis)
37
41
  @redis = redis
@@ -0,0 +1,23 @@
1
+ class Redis
2
+ module Autosuggest
3
+
4
+ class << self
5
+
6
+ # Add items to the autosuggest database from a file.
7
+ # Each line be a string representing the item
8
+ def add_from_file(file)
9
+ add(*(File.open(file, "r").map { |l| l.strip }))
10
+ end
11
+
12
+ # Add items and their to the autosuggest database from a file.
13
+ # Each line be a string representing the item followed by its score
14
+ # Example:
15
+ # item1 0.4
16
+ # item2 2.1
17
+ # item3 5.2
18
+ def add_with_score_from_file(file)
19
+ add_with_score(*(File.open(file, "r").map { |l| l.split(" ")}.flatten))
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ class Redis
2
+ module Autosuggest
3
+
4
+ class << self
5
+
6
+ def init_rails_sources
7
+ self.rails_sources.each_key do |r|
8
+ r.all.each do |record|
9
+ record.add_to_autosuggest
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+
@@ -0,0 +1,49 @@
1
+ class Redis
2
+ module Autosuggest
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+
7
+ def autosuggest(column, options={})
8
+ hash = Redis::Autosuggest.rails_sources[self]
9
+ if hash.nil?
10
+ Redis::Autosuggest.rails_sources[self] = { column => options }
11
+ else
12
+ hash[column] = options
13
+ end
14
+
15
+ # hook onto rails callbacks to update autosuggest db if a source is modified
16
+ class_eval <<-HERE
17
+ after_create :add_to_autosuggest
18
+ def add_to_autosuggest
19
+ Redis::Autosuggest.rails_sources[self.class].each do |column, options|
20
+ score = self.send(options[:rank_by]) if !options[:rank_by].nil?
21
+ score ||= 0
22
+ Redis::Autosuggest.add_with_score(self.send(column), score)
23
+ end
24
+ end
25
+
26
+ after_update :check_if_changed
27
+ def check_if_changed
28
+ Redis::Autosuggest.rails_sources[self.class].each_key do |column|
29
+ next if !self.send("#{column}_changed?")
30
+ old_item = self.send("#{column}_was")
31
+ score = Redis::Autosuggest.get_score(old_item)
32
+ Redis::Autosuggest.remove(old_item)
33
+ Redis::Autosuggest.add_with_score(self.send(column), score)
34
+ end
35
+ end
36
+
37
+ before_destroy :remove_from_autosuggest
38
+ def remove_from_autosuggest
39
+ Redis::Autosuggest.rails_sources[self.class].each_key do |column|
40
+ Redis::Autosuggest.remove(self.send(column))
41
+ end
42
+ end
43
+ HERE
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+
@@ -1,5 +1,5 @@
1
1
  class Redis
2
2
  module Autosuggest
3
- VERSION = "0.0.1"
3
+ VERSION = "0.1.0"
4
4
  end
5
5
  end
@@ -21,6 +21,5 @@ Gem::Specification.new do |gem|
21
21
  gem.add_dependency("redis", "~> 3.0.1")
22
22
  gem.add_dependency("redis-namespace", "~> 1.2.1")
23
23
 
24
- gem.add_development_dependency("debugger", "~> 1.2.0")
25
24
  gem.add_development_dependency("minitest", "~> 3.5.0")
26
25
  end
@@ -1,18 +1,9 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class TestAutosuggest < MiniTest::Unit::TestCase
4
-
4
+
5
5
  def self.unused_db
6
- @unused_db ||= Redis.new(:db => db_picker)
7
- end
8
-
9
- # get an unused db so that we can safely clear all keys
10
- def self.db_picker
11
- redis = Redis.new
12
- (0..15).each do |i|
13
- redis.select(i)
14
- return i if redis.keys.empty?
15
- end
6
+ @unused_db ||= Redis.new(:db => TestHelper.db_picker)
16
7
  end
17
8
 
18
9
  def setup
@@ -109,5 +100,10 @@ class TestAutosuggest < MiniTest::Unit::TestCase
109
100
  Redis::Autosuggest.use_leaderboard = false
110
101
  end
111
102
 
103
+ def test_getting_an_items_score
104
+ Redis::Autosuggest.add_with_score(@str1, 3)
105
+ assert_equal 3, Redis::Autosuggest.get_score(@str1)
106
+ end
107
+
112
108
  MiniTest::Unit.after_tests { self.unused_db.flushdb }
113
109
  end
data/test/file_test.rb ADDED
@@ -0,0 +1,33 @@
1
+ require 'test_helper'
2
+
3
+ class TestFile < MiniTest::Unit::TestCase
4
+
5
+ def self.unused_db
6
+ @unused_db ||= Redis.new(:db => TestHelper.db_picker)
7
+ end
8
+
9
+ def setup
10
+ self.class.unused_db.flushdb
11
+ Redis::Autosuggest.redis = self.class.unused_db
12
+ @db = Redis::Autosuggest.db
13
+ @subs = Redis::Autosuggest.substrings
14
+ end
15
+
16
+ def test_adding_from_file
17
+ Redis::Autosuggest.add_from_file("test/text/example.txt")
18
+ assert @db.hgetall(Redis::Autosuggest.items).size == 3
19
+ assert @subs.keys.size == 10
20
+ end
21
+
22
+ def test_adding_with_score_from_file
23
+ Redis::Autosuggest.add_with_score_from_file("test/text/example_with_score.txt")
24
+ assert @db.hgetall(Redis::Autosuggest.items).size == 3
25
+ assert @subs.keys.size == 10
26
+ assert_equal 12, @subs.zscore("one", 0)
27
+ assert_equal 4, @subs.zscore("two", 1)
28
+ assert_equal 3, @subs.zscore("three", 2)
29
+ end
30
+
31
+ MiniTest::Unit.after_tests { self.unused_db.flushdb }
32
+ end
33
+
data/test/test_helper.rb CHANGED
@@ -4,3 +4,15 @@ require 'debugger'
4
4
  require 'redis'
5
5
  require 'redis-namespace'
6
6
  require 'redis-autosuggest'
7
+
8
+
9
+ class TestHelper
10
+ # get an unused db so that we can safely clear all keys
11
+ def self.db_picker
12
+ redis = Redis.new
13
+ (0..15).each do |i|
14
+ redis.select(i)
15
+ return i if redis.keys.empty?
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ one
2
+ two
3
+ three
@@ -0,0 +1,3 @@
1
+ one 12
2
+ two 4
3
+ three 3
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis-autosuggest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -43,22 +43,6 @@ dependencies:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
45
  version: 1.2.1
46
- - !ruby/object:Gem::Dependency
47
- name: debugger
48
- requirement: !ruby/object:Gem::Requirement
49
- none: false
50
- requirements:
51
- - - ~>
52
- - !ruby/object:Gem::Version
53
- version: 1.2.0
54
- type: :development
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ~>
60
- - !ruby/object:Gem::Version
61
- version: 1.2.0
62
46
  - !ruby/object:Gem::Dependency
63
47
  name: minitest
64
48
  requirement: !ruby/object:Gem::Requirement
@@ -91,10 +75,16 @@ files:
91
75
  - lib/redis-autosuggest.rb
92
76
  - lib/redis/autosuggest.rb
93
77
  - lib/redis/autosuggest/config.rb
78
+ - lib/redis/autosuggest/file.rb
79
+ - lib/redis/autosuggest/init.rb
80
+ - lib/redis/autosuggest/rails.rb
94
81
  - lib/redis/autosuggest/version.rb
95
82
  - redis-autosuggest.gemspec
96
83
  - test/autosuggest_test.rb
84
+ - test/file_test.rb
97
85
  - test/test_helper.rb
86
+ - test/text/example.txt
87
+ - test/text/example_with_score.txt
98
88
  homepage: https://github.com/aphan/redis-autosuggest
99
89
  licenses: []
100
90
  post_install_message:
@@ -121,4 +111,7 @@ specification_version: 3
121
111
  summary: Suggestions/autocompletions with Redis and Ruby
122
112
  test_files:
123
113
  - test/autosuggest_test.rb
114
+ - test/file_test.rb
124
115
  - test/test_helper.rb
116
+ - test/text/example.txt
117
+ - test/text/example_with_score.txt