acts_as_suggest 0.0.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.
- checksums.yaml +15 -0
- data/Gemfile +1 -0
- data/lib/acts_as_suggest.rb +129 -0
- metadata +59 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NDM1YWQ1YWFlOWE0OTM3NzE4MjlkODIyN2UyOTgwNmM1NTQyMjc4Zg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MTFkMTJhMDE3NDZhOGYwYmNmMTM1NTU1Y2Q1YmU0NGY0ZmMxMDlmYg==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZDJmZDNmOGY1NDcxZWZlMGZjZDY3MjIxNjJhY2VmNTNhNjI4ZmMyYjFkNDRi
|
10
|
+
OWJmMTQ5OTczMmRkNzFiYTY0OWUyMTFlOWFkMWQzYTA0Y2ZhMmQzMGI5MGVj
|
11
|
+
YTk1Y2I3ZjQxMTI3OWRmMjhlMTVmMWVhMzExYWNhNDNlZmQ2MDA=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
M2NmMTNkMzFiZTQ5OWZlNDQ4NmRiOTRjMDczZTg4MzliMDY2YjY3ZjBjMzBk
|
14
|
+
YWU4YzE5Njg0ZWIyZTQwMzg1MTJlZjJhZjRjMjY5ODYyOWY5MzU1MmIzZWY2
|
15
|
+
NWMzMTBhNDQ0MTY0NTZhNWViMDU5MDE1NzRmNjU2NWI4MmVkNWU=
|
data/Gemfile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
gemspec
|
@@ -0,0 +1,129 @@
|
|
1
|
+
Gem.loaded_specs['acts_as_suggest'].dependencies.each do |d| require d.name end
|
2
|
+
|
3
|
+
require 'text'
|
4
|
+
|
5
|
+
module ActiveRecord #:nodoc:
|
6
|
+
module Acts #:nodoc:
|
7
|
+
module Suggest#:nodoc:
|
8
|
+
|
9
|
+
def self.included(base) #:nodoc:
|
10
|
+
base.extend ClassMethods
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods #:nodoc:
|
14
|
+
def acts_as_suggest
|
15
|
+
extend ActiveRecord::Acts::Suggest::SingletonMethods
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# When searching for the word "honnolullu", Google will promptly suggest "Did you mean: honolulu". This small module provides a +suggest+ method
|
20
|
+
# which enables developers to add this functionality to any model, basing the suggestion on the existing values in the table.
|
21
|
+
# Just place <tt>acts_as_suggest</tt> in a given model to mixin the method +suggest+.
|
22
|
+
#
|
23
|
+
# Example:
|
24
|
+
# class Person < ActiveRecord::Base
|
25
|
+
# acts_as_suggest
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# and then to retrieve suggestions:
|
29
|
+
#
|
30
|
+
# MyModel.suggest(:field_name, searched_value, optional_treshold)
|
31
|
+
# or
|
32
|
+
# MyModel.suggest([:field1, :field2, ...], searched_value, optional_treshold)
|
33
|
+
#
|
34
|
+
# The field_name(s) specify in what columns we need to look for the suggested/existing values.
|
35
|
+
# The searched_value is the supposedly misspelled string for which we want to retrieve corrections.
|
36
|
+
# The optional_treshold defines the tolerance level in determining the Levenshtein distance between the searched string and existing values in the database.
|
37
|
+
# If omitted, this value is calculated based on the length of the string.
|
38
|
+
module SingletonMethods
|
39
|
+
# Output:
|
40
|
+
# * If the value of +word+ exists for the specified column(s) => Records are returned (equivalent to a find(:all, :conditions => '...')
|
41
|
+
# * If the value doesn't exist in the table, but there are similar existing ones in the specified field(s) => An array of possible intended values is returned
|
42
|
+
# * If the value doesn't exist in the table and there are not enough similar strings stored => [] is returned
|
43
|
+
#
|
44
|
+
# Examples:
|
45
|
+
# Person.suggest(:city, 'Rome') #=> [#<Post:0x556fcd4 @attributes={"city"=>"Rome", "name"=>"Antonio", "id"=>"1","country"=>"Italy"}>]
|
46
|
+
# Person.suggest(:city, 'Rom') #=> ["Rome", "Roma"]
|
47
|
+
# Person.suggest([:city, :country], 'Romai'] #=> ["Rome", "Roma", "Romania"]
|
48
|
+
# Person.suggest(:city, 'Vancovvver', 1) #=> []
|
49
|
+
def suggest(fields, word, treshold = nil)
|
50
|
+
similar_results = []
|
51
|
+
# Define treshold if not explicitly specified
|
52
|
+
unless treshold
|
53
|
+
if word.size <= 4
|
54
|
+
treshold = 1
|
55
|
+
else
|
56
|
+
# Longer words should have more tolerance
|
57
|
+
treshold = word.size/3
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Checks if an array of fields is passed
|
62
|
+
if fields.kind_of?(Array)
|
63
|
+
conditions = ""
|
64
|
+
# Hash that will contain the values for the matching symbol keys
|
65
|
+
param_hash = {}
|
66
|
+
# Builds the conditions for the find method
|
67
|
+
# and fills the hash for the named parameters
|
68
|
+
fields.each_with_index do |field, i|
|
69
|
+
param_hash[field] = word
|
70
|
+
if fields.size > 1 && i < fields.size - 1
|
71
|
+
conditions += "#{field} = :#{field} OR "
|
72
|
+
else
|
73
|
+
conditions += "#{field} = :#{field}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
# Search multiple fields through named bind variables
|
77
|
+
# (for safety against tainted data)
|
78
|
+
search_results = self.find(:all, :conditions => [conditions, param_hash])
|
79
|
+
else
|
80
|
+
# Only one field to search in
|
81
|
+
search_results = self.find(:all, :conditions => ["#{fields} = ?", word])
|
82
|
+
end
|
83
|
+
|
84
|
+
# Checks if +word+ exist in the requested field(s)
|
85
|
+
if search_results.empty?
|
86
|
+
# Retrieves list of all existing values in the table
|
87
|
+
all_results = self.find(:all)
|
88
|
+
# Checks if the table is empty
|
89
|
+
unless all_results.empty?
|
90
|
+
all_results.each do |record|
|
91
|
+
if fields.kind_of?(Array)
|
92
|
+
# Adds all the strings that are similar to the one passed as a parameter (searching in the specified fields)
|
93
|
+
fields.each {|field| similar_results << record.send(field).to_s if record.send(field).to_s.similar?(word, treshold)}
|
94
|
+
else
|
95
|
+
# Adds all the strings that are similar to the one passed as a parameter (searching the single field specified only)
|
96
|
+
similar_results << record.send(fields).to_s if record.send(fields).to_s.similar?(word, treshold)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
# Remove multiple entries of the same string from the results
|
101
|
+
return similar_results.uniq
|
102
|
+
else
|
103
|
+
# The value exists in the table,
|
104
|
+
# the corrisponding records are therefore returned in an array
|
105
|
+
return search_results
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
class String
|
117
|
+
# Levenshtein distance, used to determine the minimum number
|
118
|
+
# of changes needed to modify a string into another one.
|
119
|
+
# It uses the Text gem for its UTF-8 enabled comparisons.
|
120
|
+
def distance(other)
|
121
|
+
Text::Levenshtein::distance(self, other)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Determines if two strings are similar based
|
125
|
+
# on a provided treshold.
|
126
|
+
def similar?(other, threshold = 2)
|
127
|
+
self.distance(other) <= threshold ? true : false
|
128
|
+
end
|
129
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: acts_as_suggest
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Antonio Cangiano
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: text
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
description: A simple word suggestion
|
28
|
+
email: info@antoniocangiano.com
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- Gemfile
|
34
|
+
- lib/acts_as_suggest.rb
|
35
|
+
homepage: http://rubygems.org/gems/acts_as_suggest
|
36
|
+
licenses:
|
37
|
+
- MIT
|
38
|
+
metadata: {}
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
requirements: []
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 2.2.2
|
56
|
+
signing_key:
|
57
|
+
specification_version: 4
|
58
|
+
summary: acts as sugges
|
59
|
+
test_files: []
|