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.
Files changed (4) hide show
  1. checksums.yaml +15 -0
  2. data/Gemfile +1 -0
  3. data/lib/acts_as_suggest.rb +129 -0
  4. 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: []