Class: SearchLingo::AbstractSearch
- Inherits:
-
Object
- Object
- SearchLingo::AbstractSearch
- Defined in:
- lib/search_lingo/abstract_search.rb
Instance Attribute Summary collapse
-
#query ⇒ Object
readonly
Returns the value of attribute query.
Class Method Summary collapse
-
.parser(parser = nil, &block) ⇒ Object
Adds a new parser to the list of parsers used by this class.
-
.parsers ⇒ Object
Returns an list of parsers that have been added to this class.
Instance Method Summary collapse
-
#conditions ⇒ Object
Returns an
Array
of compiled query parameters. -
#default_parse(token) ⇒ Object
Raises
NotImplementedError
. -
#initialize(query, scope) ⇒ AbstractSearch
constructor
Instantiates a new search object.
-
#load_results ⇒ Object
Constructs and performs the query.
-
#parse(token) ⇒ Object
Passes
token
to each parser in turn. -
#parsers ⇒ Object
Delegates to SearchLingo::AbstractSearch.parsers.
-
#results ⇒ Object
Returns the results of executing the search.
-
#scope ⇒ Object
Returns @scope.
-
#tokenizer ⇒ Object
Returns a
SearchLingo::Tokenizer
for @query.
Constructor Details
#initialize(query, scope) ⇒ AbstractSearch
Instantiates a new search object. query
is the string that is to be parsed and compiled into an actual query. If query
is falsey, an empty string will be used. scope
is the object to which the compiled query should be sent, e.g., an ActiveRecord
model.
12 13 14 15 |
# File 'lib/search_lingo/abstract_search.rb', line 12 def initialize(query, scope) @query = query || '' @scope = scope end |
Instance Attribute Details
#query ⇒ Object (readonly)
Returns the value of attribute query.
5 6 7 |
# File 'lib/search_lingo/abstract_search.rb', line 5 def query @query end |
Class Method Details
.parser(parser = nil, &block) ⇒ Object
Adds a new parser to the list of parsers used by this class.
The parser may be given as an anonymous block or as any argument which responds to #call
. The parser will be send #call
with a single argument which will be a token from the query string.
If both a callable object and a block are given, or if neither a callable object nor a block are given, an ArgumentError
will be raised.
class MyParser
def call(token)
# return something
end
end
class MySearch < SearchLingo::AbstractSearch
parser MyParser.new
parser do |token|
# return something
end
end
45 46 47 48 49 50 |
# File 'lib/search_lingo/abstract_search.rb', line 45 def self.parser(parser = nil, &block) unless block_given? ^ parser.respond_to?(:call) raise ArgumentError, 'parse must be called with callable OR block' end parsers << (parser || block) end |
.parsers ⇒ Object
Returns an list of parsers that have been added to this class.
19 20 21 |
# File 'lib/search_lingo/abstract_search.rb', line 19 def self.parsers @parsers ||= [] end |
Instance Method Details
#conditions ⇒ Object
Returns an Array
of compiled query parameters.
list of defined parsers. If a parser is successful, :match
is thrown, the compiled condition is saved, and processing moves on to the next token. If none of the parsers succeeds and the token is compound, that is, it has both a modifier and a term, the token is simplified, and reprocessed through the list of parsers. As during the first pass, if a parser succeeds, :match
is thrown, the compiled condition for the now simplified token is saved, and processing moves on to the next token (the remains of the original compound token). If none of the parsers succeeds during the second pass, the now simplified token is finally sent to #default_parse
, and whatever it returns will be saved as the compiled condition.
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/search_lingo/abstract_search.rb', line 87 def conditions tokenizer.inject([]) do |conditions, token| conditions << catch(:match) do # 1. Try each parser with the token until :match is thrown. parse token # 2. If :match not thrown and token is compound, simplify and try again. if token.compound? token = tokenizer.simplify parse token end # 3. If :match still not thrown, fallback on default parser. default_parse token end end end |
#default_parse(token) ⇒ Object
Raises NotImplementedError
. Classes which inherit from SearchLingo::AbstractSearch must provide their own implementation, and it should always succeed.
130 131 132 133 |
# File 'lib/search_lingo/abstract_search.rb', line 130 def default_parse(token) raise NotImplementedError, "#default_parse must be implemented by #{self.class}" end |
#load_results ⇒ Object
Constructs and performs the query.
66 67 68 69 70 |
# File 'lib/search_lingo/abstract_search.rb', line 66 def load_results conditions.inject(scope) do |query, condition| query.public_send(*condition) end end |
#parse(token) ⇒ Object
Passes token
to each parser in turn. If a parser succeeds, throws :match
with the compiled result.
A parser succeeds if call
returns a truthy value. The return value of a successful parser will be splatted and sent to @scope using public_send
.
118 119 120 121 122 123 124 |
# File 'lib/search_lingo/abstract_search.rb', line 118 def parse(token) parsers.each do |parser| result = parser.call token throw :match, result if result end nil end |
#parsers ⇒ Object
Delegates to SearchLingo::AbstractSearch.parsers.
54 55 56 |
# File 'lib/search_lingo/abstract_search.rb', line 54 def parsers self.class.parsers end |
#results ⇒ Object
Returns the results of executing the search.
60 61 62 |
# File 'lib/search_lingo/abstract_search.rb', line 60 def results @results ||= load_results end |
#scope ⇒ Object
Returns @scope.
You may override this method in your search class if you want to ensure additional messages are sent to search scope before executing the query. For example, if @scope is an ActiveRecord
model, you might want to join additional tables.
142 143 144 |
# File 'lib/search_lingo/abstract_search.rb', line 142 def scope @scope end |