awesome_search 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +121 -0
- data/Rakefile +72 -0
- data/VERSION +1 -0
- data/awesome_search.gemspec +70 -0
- data/init.rb +1 -0
- data/lib/awesome/definitions/bits.rb +74 -0
- data/lib/awesome/definitions/filters.rb +72 -0
- data/lib/awesome/definitions/locales.rb +69 -0
- data/lib/awesome/definitions/types.rb +93 -0
- data/lib/awesome/search.rb +146 -0
- data/lib/awesome/super_search.rb +16 -0
- data/lib/awesome/triage.rb +122 -0
- data/lib/awesome_search.rb +7 -0
- data/rails/init.rb +3 -0
- data/test/helper.rb +128 -0
- data/test/search_classes/amazon.rb +6 -0
- data/test/search_classes/ebay.rb +6 -0
- data/test/search_classes/google.rb +6 -0
- data/test/search_classes/local.rb +6 -0
- data/test/test_awesome_search.rb +66 -0
- data/test/test_multiple.rb +24 -0
- data/test/test_multiple_filters.rb +31 -0
- data/test/test_multiple_locales.rb +24 -0
- data/test/test_multiple_types.rb +42 -0
- metadata +110 -0
@@ -0,0 +1,146 @@
|
|
1
|
+
module Awesome
|
2
|
+
class Search
|
3
|
+
|
4
|
+
# Mixins
|
5
|
+
include Definitions::Bits
|
6
|
+
include Definitions::Types
|
7
|
+
include Definitions::Filters
|
8
|
+
include Definitions::Stopwords
|
9
|
+
|
10
|
+
@@search_types ||= {:search_types_to_type_modifiers => {},
|
11
|
+
:search_type_inceptions => {},
|
12
|
+
:search_type_regexes => {}}
|
13
|
+
@@search_filters ||= {:search_filters_to_filter_modifiers => {},
|
14
|
+
:filter_modifiers_to_search_filters => {}}
|
15
|
+
|
16
|
+
#Some defaults if stopwords are set to be used (by default they are turned off)
|
17
|
+
@@search_stopwords ||= {:standard => %w(an and are as at be but by for if in into is it no not of on or s such t that the their then there these they this to was will with),
|
18
|
+
:custom => []}
|
19
|
+
|
20
|
+
def self.configure_search_types(&block)
|
21
|
+
yield @@search_types
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.configure_search_filters(&block)
|
25
|
+
yield @@search_filters
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.configure_search_stopwords(&block)
|
29
|
+
yield @@search_stopwords
|
30
|
+
end
|
31
|
+
|
32
|
+
#TODO: Put these into a config block
|
33
|
+
cattr_accessor :verbose
|
34
|
+
cattr_accessor :check_inception
|
35
|
+
cattr_accessor :protect_types
|
36
|
+
cattr_accessor :protect_filters
|
37
|
+
|
38
|
+
attr_accessor(:search_text,
|
39
|
+
:search_query,
|
40
|
+
:search_type,
|
41
|
+
:search_filters,
|
42
|
+
:search_locale,
|
43
|
+
:stopwords,
|
44
|
+
:found,
|
45
|
+
:tally,
|
46
|
+
:success,
|
47
|
+
:endpoint,
|
48
|
+
:invalid_inception,
|
49
|
+
:redirect_url,
|
50
|
+
:page,
|
51
|
+
:per_page,
|
52
|
+
:replacement_for,
|
53
|
+
:multiple_types_as_one,
|
54
|
+
:tokenize_quoted,
|
55
|
+
:tokenize_unquoted,
|
56
|
+
:tokenize_without_quoted,
|
57
|
+
:quoted_exact_phrases,
|
58
|
+
:unquoted_exact_phrases,
|
59
|
+
:query_without_exact_phrases,
|
60
|
+
:gowords,
|
61
|
+
:search_tokens,
|
62
|
+
:highlight_tokens)
|
63
|
+
|
64
|
+
#CLASS METHODS
|
65
|
+
#Main focus of class methods is determining which sort of AwesomeSearch subclass we need to instantiate for the search
|
66
|
+
def initialize(*args)
|
67
|
+
@multiple_types_as_one = args.first[:multiple_types_as_one]
|
68
|
+
@stopwords = args.first[:stopwords] ?
|
69
|
+
args.first[:stopwords].is_a?(Array) ?
|
70
|
+
args.first[:stopwords] :
|
71
|
+
args.first[:stopwords].is_a?(Symbol) ?
|
72
|
+
self.class.stopwords(args.first[:stopwords]) :
|
73
|
+
self.class.stopwords(:both) :
|
74
|
+
args.first[:stopwords] != false ?
|
75
|
+
self.class.stopwords(:standard) :
|
76
|
+
[]
|
77
|
+
@page = args.first[:page]
|
78
|
+
@per_page = args.first[:per_page]
|
79
|
+
@search_text = args.first[:search_text] # a string
|
80
|
+
@search_filters = args.first[:search_filters] # a ruby object (string, array, hash) to be used by subclasss search classes as a filter
|
81
|
+
#Chicken-egg problem: search_tokens and highlight_tokens both need to be set within clean_search_text (and they are!) because they must work with the text cleaned by the clean_search_text methods
|
82
|
+
@search_tokens = args.first[:search_tokens] # an array of the query terms as tokens after being cleaned, unless passed in as param (not sure why this would ever be desired, but why not allow it jic?) When not set in args, will be set by clean_search_text methods
|
83
|
+
@highlight_tokens = args.first[:highlight_tokens] # an array of the query terms as unquoted tokens after being cleaned, unless passed in as param (not sure why this would ever be desired, but why not allow it jic?) When not set in args, will be set by clean_search_text methods
|
84
|
+
@search_query = self.clean_search_text # a string to be set based on the search text by removing the search modifiers from the search text
|
85
|
+
@search_type = args.first[:search_type] # a symring (symring methods are in the Bits mixin)
|
86
|
+
@search_locale = args.first[:search_locale] # a symring (symring methods are in the Bits mixin)
|
87
|
+
@found = nil
|
88
|
+
@tally = nil
|
89
|
+
@success = true
|
90
|
+
@redirect_url = nil
|
91
|
+
@replacement_for = nil # stores the name of, or explanatory text about, the primary search if this search is a secondary (replacement) search for a primary search that returned no results
|
92
|
+
if self.class.check_inception && !self.valid_search_type_inception?
|
93
|
+
puts "search type inception is invalid (no type regex matches query string)" if Awesome::Search.verbose
|
94
|
+
@invalid_inception = true
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_s
|
99
|
+
"search_query: #{self.search_query} \
|
100
|
+
\n\rsearch_tokens: #{self.search_tokens.inspect} \
|
101
|
+
\n\rhighlight_tokens: #{self.highlight_tokens.inspect} \
|
102
|
+
\n\rtally: #{self.tally} \
|
103
|
+
\n\rsuccess? #{self.success ? 'Yes' : 'No'}"
|
104
|
+
end
|
105
|
+
|
106
|
+
def clean_search_text
|
107
|
+
txt = Awesome::Triage.clean_search_text(self.search_text)
|
108
|
+
txt = Awesome::Search.clean_search_text(txt, self.multiple_types_as_one)
|
109
|
+
txt = self.process_stopwords(txt)
|
110
|
+
txt
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.clean_search_text(text, multiple_types_as_one = false)
|
114
|
+
txt = text.gsub(self.search_type_modifiers_regex(true, multiple_types_as_one), "")
|
115
|
+
txt.gsub(self.search_filter_modifiers_regex(true), "")
|
116
|
+
end
|
117
|
+
|
118
|
+
# Main method used by the app to search
|
119
|
+
# Instantiates an Awesome::Triage which will handle setting up the search
|
120
|
+
def self.results_for(anytext, types, locales, filters = nil, multiple_types_as_one = false, page = nil, per_page = nil)
|
121
|
+
# 1. if the search is blank return nil
|
122
|
+
puts "anytext is blank" if Awesome::Search.verbose && anytext.blank?
|
123
|
+
return nil if anytext.blank?
|
124
|
+
Triage.new(:text => anytext, :types => types, :locales => locales, :filters => filters, :multiple_types_as_one => multiple_types_as_one, :page => page, :per_page => per_page)
|
125
|
+
end
|
126
|
+
|
127
|
+
#INSTANCE METHODS
|
128
|
+
|
129
|
+
# get_results is called on the instances of the subclasses.
|
130
|
+
# The subclasses override the methods called within it to return their customized stuff
|
131
|
+
# The subclasses call super to ensure that the data is valid before sending out the search.
|
132
|
+
def get_results
|
133
|
+
# 1. if the search is blank do NOT run the search (handled in subclasses)
|
134
|
+
!self.search_text.blank? && !self.search_query.blank? && !self.search_type.blank? && !self.search_locale.blank?
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
#handles a param of any string, and returns all known matches for that string
|
140
|
+
#def self.all_matches(search_text = "")
|
141
|
+
# self.match_types(search_text).map do |type|
|
142
|
+
# {type => self.matches_for_type(type, search_text, true)}
|
143
|
+
# end.compact | self.match_types(search_text).map do |type|
|
144
|
+
# {type => self.matches_for_type(type, search_text, false)}
|
145
|
+
# end.compact
|
146
|
+
#end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Awesome
|
2
|
+
class SuperSearch < Awesome::Search
|
3
|
+
# Instance method Mixins
|
4
|
+
def get_results
|
5
|
+
return nil unless super
|
6
|
+
# initialize the search result values since
|
7
|
+
# if we've gotten this far we have a real search being executed
|
8
|
+
# tally and results are set to nil in the main initializer
|
9
|
+
# so that we can differentiate between searches that aborted
|
10
|
+
# and searches that completed but had no results.
|
11
|
+
self.found = []
|
12
|
+
self.tally = 0
|
13
|
+
return true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module Awesome
|
2
|
+
class Triage < Array
|
3
|
+
|
4
|
+
# Mixins
|
5
|
+
include Definitions::Bits
|
6
|
+
include Definitions::Locales
|
7
|
+
|
8
|
+
#The following is set in a config block
|
9
|
+
@@search_locales ||= {:search_locales_to_classes => {},
|
10
|
+
:search_locales_to_locale_modifiers => {},
|
11
|
+
:locale_modifiers_to_search_locales => {},
|
12
|
+
:search_locales_to_stopwords => {}}
|
13
|
+
|
14
|
+
def self.configure_search_locales(&block)
|
15
|
+
yield @@search_locales
|
16
|
+
end
|
17
|
+
|
18
|
+
#TODO: Put these into a config block
|
19
|
+
cattr_accessor :verbose
|
20
|
+
|
21
|
+
attr_accessor( :text,
|
22
|
+
:types,
|
23
|
+
:locales,
|
24
|
+
:filters,
|
25
|
+
:multiple_types_as_one,
|
26
|
+
:redirect_url,
|
27
|
+
:page,
|
28
|
+
:per_page )
|
29
|
+
|
30
|
+
def initialize(*args)
|
31
|
+
super()
|
32
|
+
@multiple_types_as_one = !args.first[:multiple_types_as_one].nil? ? args.first[:multiple_types_as_one] : false# Boolean: should the array of types be sent through to a single search, or iterated over to separate searches like locales?
|
33
|
+
@page = args.first[:page]
|
34
|
+
@per_page = args.first[:per_page]
|
35
|
+
@text = args.first[:text] # a string
|
36
|
+
@types = args.first[:types].respond_to?(:each) ? args.first[:types] : [args.first[:types]] # a symring, or array thereof (symring methods are in the Bits mixin)
|
37
|
+
@locales = args.first[:locales].respond_to?(:each) ? args.first[:locales] : [args.first[:locales]] # a symring, or array thereof (symring methods are in the Bits mixin)
|
38
|
+
@filters = args.first[:filters] # a ruby object (string, array, hash) to be used by subclasss search classes as a filter
|
39
|
+
@redirect_url = nil
|
40
|
+
# 1. Handle all locale modifiers, by creating a different search for each
|
41
|
+
self.locales.each do |locale|
|
42
|
+
puts "initializing locale: #{locale}" if self.class.verbose_locales
|
43
|
+
locale = self.class.make_symring(locale)
|
44
|
+
klass = self.class.get_class_for_locale(locale)
|
45
|
+
# 2. if there is no matching class for the locale return nil
|
46
|
+
puts "klass is nil" if Awesome::Triage.verbose && klass.nil?
|
47
|
+
next if klass.nil?
|
48
|
+
# 3. If there is a locale modifier, then make sure it matches the locale being searched or return nil
|
49
|
+
locale_mods = self.class.valid_locale_modifiers(self.text, locale)
|
50
|
+
puts "locale_mods is empty" if Awesome::Triage.verbose && locale_mods.empty?
|
51
|
+
next if locale_mods.empty?
|
52
|
+
self.add_search(klass, locale, self.class.stopwords_for_locale(locale))
|
53
|
+
#if we hit a search that tells us to redirect, do not continue
|
54
|
+
break if self.redirect_url
|
55
|
+
end
|
56
|
+
self.compact!
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_search(klass, locale, stopwords)
|
61
|
+
# 4. Handle all type modifiers, by creating a different search for each
|
62
|
+
if self.multiple_types_as_one
|
63
|
+
new_search = self.new_search_for_types_and_locale(klass, self.types, locale, stopwords)
|
64
|
+
self.redirect_url = new_search.redirect_url
|
65
|
+
self << new_search
|
66
|
+
else
|
67
|
+
self.types.each do |typ|
|
68
|
+
new_search = self.new_search_for_type_and_locale(klass, typ, locale, stopwords)
|
69
|
+
self.redirect_url = new_search.redirect_url
|
70
|
+
self << new_search
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# single type
|
76
|
+
def new_search_for_type_and_locale(klass, type, locale, stopwords)
|
77
|
+
new_search = nil
|
78
|
+
type = self.class.make_symring(type)
|
79
|
+
# 6. If there is a type modifier, then make sure it matches the type being searched or return nil
|
80
|
+
valid_type_mods = Awesome::Search.protect_types ? klass.valid_type_modifiers(self.text, type, self.multiple_types_as_one) : [type]
|
81
|
+
puts "valid_type_mods is empty" if Awesome::Triage.verbose && valid_type_mods.empty?
|
82
|
+
unless valid_type_mods.empty?
|
83
|
+
new_search = klass.new({:stopwords => stopwords, :multiple_types_as_one => self.multiple_types_as_one, :search_text => self.text, :search_type => type, :search_locale => locale, :search_filters => self.filter_mods(klass), :page => self.page, :per_page => self.per_page})
|
84
|
+
new_search.get_results
|
85
|
+
end
|
86
|
+
return new_search
|
87
|
+
end
|
88
|
+
|
89
|
+
# multiple types
|
90
|
+
def new_search_for_types_and_locale(klass, types, locale, stopwords)
|
91
|
+
new_search = nil
|
92
|
+
# 6. If there is a type modifier, then make sure it matches the type being searched or return nil
|
93
|
+
valid_type_mods = klass.protect_types ? klass.valid_type_modifiers(self.text, types, self.multiple_types_as_one) : types
|
94
|
+
puts "valid_type_mods is empty" if Awesome::Triage.verbose && valid_type_mods.empty?
|
95
|
+
unless valid_type_mods.empty?
|
96
|
+
new_search = klass.new({:stopwords => stopwords, :multiple_types_as_one => self.multiple_types_as_one, :search_text => self.text, :search_type => valid_type_mods, :search_locale => locale, :search_filters => self.filter_mods(klass), :page => self.page, :per_page => self.per_page})
|
97
|
+
new_search.get_results
|
98
|
+
end
|
99
|
+
return new_search
|
100
|
+
end
|
101
|
+
|
102
|
+
def filter_mods(klass)
|
103
|
+
valid_filter_mods = nil
|
104
|
+
if self.filters
|
105
|
+
# 5. If there is a filter modifier, then make sure it matches the locale being searched or return nil
|
106
|
+
valid_filter_mods = Awesome::Search.protect_filters ? klass.valid_filter_modifiers(self.text, self.filters) : self.filters
|
107
|
+
puts "valid_filter_mods is empty" if Awesome::Triage.verbose && valid_filter_mods.empty?
|
108
|
+
end
|
109
|
+
valid_filter_mods
|
110
|
+
end
|
111
|
+
|
112
|
+
def clean_search_text
|
113
|
+
txt = Awesome::Triage.clean_search_text(self.search_text)
|
114
|
+
Awesome::Search.clean_search_text(txt, self.multiple_types_as_one)
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.clean_search_text(text)
|
118
|
+
text.gsub(self.search_locale_modifiers_regex(true), "")
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
require "awesome/definitions/bits" unless defined?(Awesome::Definitions::Bits)
|
2
|
+
require "awesome/definitions/locales" unless defined?(Awesome::Definitions::Locales)
|
3
|
+
require "awesome/definitions/filters" unless defined?(Awesome::Definitions::Filters)
|
4
|
+
require "awesome/definitions/types" unless defined?(Awesome::Definitions::Types)
|
5
|
+
require "awesome/triage" unless defined?(Awesome::Triage)
|
6
|
+
require "awesome/search" unless defined?(Awesome::Search)
|
7
|
+
require "awesome/super_search" unless defined?(Awesome::SuperSearch)
|
data/rails/init.rb
ADDED
data/test/helper.rb
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'shoulda'
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
6
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
7
|
+
require File.join(File.dirname(__FILE__), "..", "init")
|
8
|
+
|
9
|
+
require "test/search_classes/amazon"
|
10
|
+
require "test/search_classes/ebay"
|
11
|
+
require "test/search_classes/google"
|
12
|
+
require "test/search_classes/local"
|
13
|
+
|
14
|
+
class Test::Unit::TestCase
|
15
|
+
Awesome::Search.protect_types = true
|
16
|
+
Awesome::Search.protect_filters = true
|
17
|
+
Awesome::Search.verbose = false
|
18
|
+
Awesome::Search.verbose_types = false
|
19
|
+
Awesome::Search.verbose_filters = false
|
20
|
+
Awesome::Triage.verbose = false
|
21
|
+
Awesome::Triage.verbose_locales = false
|
22
|
+
|
23
|
+
Awesome::Triage.configure_search_locales do |config|
|
24
|
+
config[:search_locales_to_classes] =
|
25
|
+
{ ":local" => "Local",
|
26
|
+
":amazon" => "Amazon",
|
27
|
+
":google" => "Google",
|
28
|
+
":ebay" => "Ebay" }
|
29
|
+
config[:search_locales_to_locale_modifiers] =
|
30
|
+
{
|
31
|
+
":local" =>
|
32
|
+
[ ":local" ],
|
33
|
+
":amazon" =>
|
34
|
+
[ ":amazon",
|
35
|
+
":amzn",
|
36
|
+
":amz",
|
37
|
+
":am"],
|
38
|
+
":google" =>
|
39
|
+
[ ":google",
|
40
|
+
":goog",
|
41
|
+
":goo",
|
42
|
+
":go"],
|
43
|
+
":ebay" =>
|
44
|
+
[ ":ebay",
|
45
|
+
":eby",
|
46
|
+
":eb"]
|
47
|
+
}
|
48
|
+
config[:locale_modifiers_to_search_locales] =
|
49
|
+
{
|
50
|
+
":local" => ":local",
|
51
|
+
":amazon" => ":amazon",
|
52
|
+
":amz" => ":amazon",
|
53
|
+
":amzn" => ":amazon",
|
54
|
+
":am" => ":amazon",
|
55
|
+
":google" => ":google",
|
56
|
+
":goog" => ":google",
|
57
|
+
":goo" => ":google",
|
58
|
+
":go" => ":google",
|
59
|
+
":ebay" => ":ebay",
|
60
|
+
":eby" => ":ebay",
|
61
|
+
":eb" => ":ebay"
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
Awesome::Search.configure_search_types do |config|
|
66
|
+
config[:search_types_to_type_modifiers] =
|
67
|
+
{
|
68
|
+
":isbn" => ":isbn",
|
69
|
+
":sku" => ":sku",
|
70
|
+
":upc" => ":upc",
|
71
|
+
":asin" => ":asin",
|
72
|
+
":id" => ":dbid",
|
73
|
+
":text" => ":text"
|
74
|
+
}
|
75
|
+
# When using observer, how long should we wait before sending out search queries?
|
76
|
+
config[:search_type_inceptions] =
|
77
|
+
{
|
78
|
+
":isbn" => 10,
|
79
|
+
":sku" => 8,
|
80
|
+
":upc" => 10,
|
81
|
+
":asin" => 10,
|
82
|
+
":id" => 1,
|
83
|
+
":text" => 4
|
84
|
+
}
|
85
|
+
config[:search_type_regexes] =
|
86
|
+
{
|
87
|
+
":isbn" => /\d{10}$|^\d{13}/, #match 10 or 13 digits for isbn
|
88
|
+
":sku" => /[0-9a-zA-Z\-]+/, #match any alphanumeric
|
89
|
+
":upc" => /\d{10}$|^\d{12}/,
|
90
|
+
":asin" => /\w{10}/,
|
91
|
+
":id" => /\d+/,
|
92
|
+
":text" => /\w{4}/
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
Awesome::Search.configure_search_filters do |config|
|
97
|
+
config[:search_filters_to_filter_modifiers] =
|
98
|
+
{
|
99
|
+
":all" =>
|
100
|
+
[ ":all",
|
101
|
+
":every" ],
|
102
|
+
":spotted" =>
|
103
|
+
[ "spotted" ],
|
104
|
+
":old" =>
|
105
|
+
[ ":old",
|
106
|
+
":ancient",
|
107
|
+
":wrinkly",
|
108
|
+
":grey"],
|
109
|
+
":new" =>
|
110
|
+
[ ":new",
|
111
|
+
":shiny",
|
112
|
+
":fresh"]
|
113
|
+
}
|
114
|
+
config[:filter_modifiers_to_search_filters] =
|
115
|
+
{
|
116
|
+
":all" => ":all",
|
117
|
+
":every" => ":all",
|
118
|
+
":spotted" => ":spotted",
|
119
|
+
":old" => ":old",
|
120
|
+
":ancient" => ":old",
|
121
|
+
":wrinkly" => ":old",
|
122
|
+
":grey" => ":old",
|
123
|
+
":new" => ":new",
|
124
|
+
":shiny" => ":new",
|
125
|
+
":fresh" => ":new"
|
126
|
+
}
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
class TestAwesomeSearch < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "An Awesome::Search instance" do
|
6
|
+
setup do
|
7
|
+
@awesome = Awesome::Search.new({:search_text => "this is a test", :search_type => :isbn, :search_locale => :amazon})
|
8
|
+
end
|
9
|
+
|
10
|
+
should "return search_query" do
|
11
|
+
assert_equal 'this is a test', @awesome.search_query
|
12
|
+
end
|
13
|
+
should "return search_type" do
|
14
|
+
assert_equal :isbn, @awesome.search_type
|
15
|
+
end
|
16
|
+
should "return search_locale" do
|
17
|
+
assert_equal :amazon, @awesome.search_locale
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "An Awesome::Search instance with query modifiers" do
|
22
|
+
setup do
|
23
|
+
@awesome = Awesome::Search.new({:search_text => ":ebay :sku this is a test"})
|
24
|
+
end
|
25
|
+
|
26
|
+
should "return search_query without query modifiers" do
|
27
|
+
assert_equal 'this is a test', @awesome.search_query
|
28
|
+
end
|
29
|
+
should "search_type should be nil" do
|
30
|
+
assert_equal nil, @awesome.search_type
|
31
|
+
end
|
32
|
+
should "return search_locale" do
|
33
|
+
assert_equal nil, @awesome.search_locale
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "#results_for with invalid params" do
|
38
|
+
setup do
|
39
|
+
@invalid_search = Awesome::Search.results_for(":local :text this is a test", ":upc", ":ebay")
|
40
|
+
end
|
41
|
+
|
42
|
+
should "invalid search should return nil" do
|
43
|
+
assert @invalid_search.empty?
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "#results_for with valid params" do
|
48
|
+
setup do
|
49
|
+
@searches = Awesome::Search.results_for(":local :amazon :text :isbn this is a test", ":text", ":local")
|
50
|
+
end
|
51
|
+
|
52
|
+
should "should return an array" do
|
53
|
+
assert @searches.is_a?(Array)
|
54
|
+
end
|
55
|
+
|
56
|
+
should "for a single type, get a single result set" do
|
57
|
+
assert @searches.length == 1
|
58
|
+
end
|
59
|
+
should "for a single type result set has results" do
|
60
|
+
assert !@searches.first.found.nil?
|
61
|
+
end
|
62
|
+
should "valid search should return integer tally" do
|
63
|
+
assert @searches.first.tally.is_a?(Integer)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
class TestMultiple < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "#results_for with multiple types AND multiple locales" do
|
6
|
+
setup do
|
7
|
+
@searches = Awesome::Search.results_for(":local :amazon :text :isbn this is a test 1234567890", [":text",":isbn"], [":local",":amazon"])
|
8
|
+
end
|
9
|
+
should "should return an array" do
|
10
|
+
assert @searches.is_a?(Array)
|
11
|
+
end
|
12
|
+
|
13
|
+
should "returns multiple result sets" do
|
14
|
+
assert @searches.length > 1
|
15
|
+
end
|
16
|
+
should "all have results" do
|
17
|
+
assert @searches.select {|x| x.found.is_a?(Array)}.length == 4
|
18
|
+
end
|
19
|
+
should "all have tally" do
|
20
|
+
assert @searches.select {|x| x.tally.is_a?(Integer)}.length == 4
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
class TestMultipleFilters < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "#results_for with multiple filters" do
|
6
|
+
setup do
|
7
|
+
@searches = Awesome::Search.results_for(":local :amazon :text :isbn :old this is a test 1234567890", ":text", ":local", [":old",":spotted",":shiny",":new"])
|
8
|
+
end
|
9
|
+
should "should return an array" do
|
10
|
+
assert @searches.is_a?(Array)
|
11
|
+
end
|
12
|
+
|
13
|
+
should "returns 1 result set per type:locale combination" do
|
14
|
+
assert @searches.length == 1
|
15
|
+
end
|
16
|
+
should "all have results" do
|
17
|
+
assert @searches.select {|x| x.found.is_a?(Array)}.length == 1
|
18
|
+
end
|
19
|
+
should "all have tally" do
|
20
|
+
assert @searches.select {|x| x.tally.is_a?(Integer)}.length == 1
|
21
|
+
end
|
22
|
+
should "all have search_filters" do
|
23
|
+
assert @searches.select {|x| !x.search_filters.nil?}.length == 1
|
24
|
+
end
|
25
|
+
should "have search_filters == [':old',':spotted',':new']" do
|
26
|
+
#:shiny is filtered out, as it is not a filter mod for the backend, only an alias for the front end
|
27
|
+
assert @searches.select {|x| x.search_filters == [":old",":spotted",":new"]}.length == 1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
class TestMultipleLocales < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "#results_for with multiple locales" do
|
6
|
+
setup do
|
7
|
+
@searches = Awesome::Search.results_for(":local :amazon :text :isbn this is a test", ":text", [":local",":amazon"])
|
8
|
+
end
|
9
|
+
should "should return an array" do
|
10
|
+
assert @searches.is_a?(Array)
|
11
|
+
end
|
12
|
+
|
13
|
+
should "returns 1 result set per type:locale combination" do
|
14
|
+
assert @searches.length == 2
|
15
|
+
end
|
16
|
+
should "all have results" do
|
17
|
+
assert @searches.select {|x| x.found.is_a?(Array)}.length == 2
|
18
|
+
end
|
19
|
+
should "all have tally" do
|
20
|
+
assert @searches.select {|x| x.tally.is_a?(Integer)}.length == 2
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
class TestMultipleTypes < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "#results_for with multiple types as multiple types" do
|
6
|
+
setup do
|
7
|
+
@searches = Awesome::Search.results_for(":local :amazon :text :isbn this is a test 1234567890", [":text", ":isbn"], ":local")
|
8
|
+
end
|
9
|
+
should "should return an array" do
|
10
|
+
assert @searches.is_a?(Array)
|
11
|
+
end
|
12
|
+
|
13
|
+
should "returns 1 result set per type:locale combination" do
|
14
|
+
assert @searches.length == 2
|
15
|
+
end
|
16
|
+
should "all have results" do
|
17
|
+
assert @searches.select {|x| x.found.is_a?(Array)}.length == 2
|
18
|
+
end
|
19
|
+
should "all have tally" do
|
20
|
+
assert @searches.select {|x| x.tally.is_a?(Integer)}.length == 2
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "#results_for with multiple types as single type" do
|
25
|
+
setup do
|
26
|
+
@searches = Awesome::Search.results_for(":local :amazon :text :isbn this is a test 1234567890", [":text", ":isbn"], ":local", nil, true)
|
27
|
+
end
|
28
|
+
should "should return an array" do
|
29
|
+
assert @searches.is_a?(Array)
|
30
|
+
end
|
31
|
+
|
32
|
+
should "returns 1 result set per type:locale combination" do
|
33
|
+
assert @searches.length == 1
|
34
|
+
end
|
35
|
+
should "all have results" do
|
36
|
+
assert @searches.select {|x| x.found.is_a?(Array)}.length == 1
|
37
|
+
end
|
38
|
+
should "all have tally" do
|
39
|
+
assert @searches.select {|x| x.tally.is_a?(Integer)}.length == 1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|