Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial commit: LuceneQuery, examples and Rakefile
- Loading branch information
Jeremy Voorhis
committed
Apr 30, 2008
0 parents
commit 44b5d26
Showing
3 changed files
with
193 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
require 'rake' | ||
require 'spec/rake/spectask' | ||
|
||
desc "Run all examples" | ||
Spec::Rake::SpecTask.new('examples') do |t| | ||
t.spec_files = FileList['examples/**/*.rb'] | ||
end | ||
|
||
task :default => :examples |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
require File.dirname(__FILE__) + '/../lib/lucene_query' | ||
|
||
describe LuceneQuery do | ||
|
||
it "should passthru most primitives" do | ||
lambda { :example }.should generate_query("example") | ||
lambda { 42 }.should generate_query("42") | ||
lambda { 3.14159 }.should generate_query("3.14159") | ||
lambda { true }.should generate_query("true") | ||
lambda { false }.should generate_query("false") | ||
end | ||
|
||
it "should quote Strings" do | ||
lambda { "example" }.should generate_query("'example'") | ||
end | ||
|
||
it "should group Arrays" do | ||
lambda { [:red, :green, :blue] }.should generate_query("(red green blue)") | ||
end | ||
|
||
it "should join terms with AND" do | ||
lambda { And(:symbol, 42, "string") }.should generate_query("(symbol AND 42 AND 'string')") | ||
end | ||
|
||
it "should join terms with OR" do | ||
lambda { Or(:symbol, 42, "string") }.should generate_query("(symbol OR 42 OR 'string')") | ||
end | ||
|
||
it "should support fields" do | ||
lambda { Field(:city, "Portland") }.should generate_query("city:'Portland'") | ||
lambda { Field("city", "Portland") }.should generate_query("'city':'Portland'") | ||
end | ||
|
||
it "should AND together Hash terms" do | ||
lambda { { :city => "Portland", :state => "Oregon" } }.should generate_query("(state:'Oregon' AND city:'Portland')") | ||
end | ||
|
||
it "should OR together IN terms" do | ||
lambda { In(:id, [110, 220, 330]) }.should generate_query("(id:110 OR id:220 OR id:330)") | ||
end | ||
|
||
it "should require terms" do | ||
lambda { Required("lucene") }.should generate_query("+'lucene'") | ||
lambda { { :marine_life => [Required("fish"), Required("dolphins")] } }.should generate_query("(marine_life:(+'fish' +'dolphins'))") | ||
end | ||
|
||
it "should prohibit terms" do | ||
lambda { Prohibit("bugs") }.should generate_query("-'bugs'") | ||
lambda { { :marine_life => [Required("fish"), Prohibit("eels")] } }.should generate_query("(marine_life:(+'fish' -'eels'))") | ||
end | ||
end | ||
|
||
class QueryMatcher | ||
def initialize(expected) | ||
@expected = expected | ||
end | ||
|
||
def matches?(target) | ||
@target = target | ||
@actual = LuceneQuery.new(&@target).to_s | ||
@expected == @actual | ||
end | ||
|
||
def failure_message | ||
"\tExpected\n#@expected\n\tbut received\n#@actual" | ||
end | ||
end | ||
|
||
def generate_query(query) | ||
QueryMatcher.new(query) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
class LuceneQuery | ||
## Syntax Nodes | ||
::String.class_eval do | ||
def to_lucene; "'#{escape_lucene}'" end | ||
def parens; "(#{self})" end | ||
def escape_lucene | ||
gsub(/([-+!\(\)\{\}\[\]^"~*?:\\]|&&|\|\|)/) { |m| "\\#{m}" } | ||
end | ||
end | ||
|
||
::Symbol.class_eval do | ||
def to_lucene; to_s end | ||
end | ||
|
||
::Array.class_eval do | ||
def to_lucene | ||
hd, *tl = self | ||
tl.inject(hd.to_lucene) { |q,t| q + " " + t.to_lucene }.parens | ||
end | ||
end | ||
|
||
::Hash.class_eval do | ||
def to_lucene | ||
inner = map { |k,v| Field.new(k, v) } | ||
LuceneQuery::And.new(*inner).to_lucene | ||
end | ||
end | ||
|
||
::Numeric.module_eval do | ||
def to_lucene; to_s end | ||
end | ||
|
||
::TrueClass.class_eval do | ||
def to_lucene; to_s end | ||
end | ||
|
||
::FalseClass.class_eval do | ||
def to_lucene; to_s end | ||
end | ||
|
||
class Field | ||
def initialize(key, val) | ||
@key, @val = key, val | ||
end | ||
|
||
def to_lucene | ||
@key.to_lucene + ":" + @val.to_lucene | ||
end | ||
end | ||
|
||
class BooleanOperator | ||
def initialize(*terms) @terms = terms end | ||
|
||
def to_lucene | ||
hd, *tl = @terms | ||
tl.inject(hd.to_lucene) { |q,t| | ||
q + " " + operator + " " + t.to_lucene | ||
}.parens | ||
end | ||
end | ||
|
||
class And < BooleanOperator | ||
def operator; "AND" end | ||
end | ||
|
||
class Or < BooleanOperator | ||
def operator; "OR" end | ||
end | ||
|
||
class Not | ||
def initialize(term) @term = term end | ||
|
||
def to_lucene | ||
"NOT #{@term.to_lucene}" | ||
end | ||
end | ||
|
||
class Required | ||
def initialize(term) @term = term end | ||
|
||
def to_lucene | ||
"+" + @term.to_lucene | ||
end | ||
end | ||
|
||
class Prohibit | ||
def initialize(term) @term = term end | ||
|
||
def to_lucene | ||
"-" + @term.to_lucene | ||
end | ||
end | ||
|
||
## DSL Helpers | ||
def Field(key, val) Field.new(key, val) end | ||
def And(*terms) And.new(*terms) end | ||
def Or(*terms) Or.new(*terms) end | ||
def In(field, terms) | ||
Or.new(*terms.map { |term| Field.new(field, term) }) | ||
end | ||
def Not(term) Not.new(term) end | ||
def Required(term) Required.new(term) end | ||
def Prohibit(term) Prohibit.new(term) end | ||
|
||
def initialize(&block) | ||
@term = instance_eval(&block) | ||
end | ||
|
||
def to_s; @term.to_lucene end | ||
alias :to_str :to_s | ||
end | ||
|
||
SolrQuery = LuceneQuery unless defined?(SolrQuery) |