Skip to content

Instantly share code, notes, and snippets.

@ryandotsmith
Created July 2, 2010 16:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ryandotsmith/461569 to your computer and use it in GitHub Desktop.
Save ryandotsmith/461569 to your computer and use it in GitHub Desktop.
prototype of a search engine i built for GS Enterprises
require 'extensions/all'
class String
def peel()
return nil if self.length.zero?
self.strip
end
end
class Seeker
attr_accessor :origin, :destination, :includes, :query
def initialize( string, radius=150, object=nil )
@q_string = string
@includes = []
@radius = radius
@scope_object = object
end
def run()
self.filter_query()
self.build_query()
self.scope( self.execute() )
end
def filter_query()
# if the query specifies an object, pick it from string
if !@q_string.scan(/:/).length.zero? # string has a : and possibly a -
@includes << @q_string.split(':').first.strip
remainder = @q_string.split(':').second
if !remainder.scan(/-/).length.zero? #string has a -
remainder.strip!
if remainder.starts_with?('-') # no origin was defined
@destination = remainder.split('-').last.strip.peel
elsif remainder.ends_with?('-')# no destination was defined
@origin = remainder.split('-').first.strip.peel
else # ambiguous location
@origin = remainder.split('-').first.strip.peel
@destination = remainder.split('-').last.strip.peel
end
else # string does not have a -
@origin = remainder.strip
@destination = remainder.strip
end
elsif !@q_string.scan(/-/).length.zero? # string has - but not a :
@includes = ['lanes','bids']
if @q_string.first == "-"
@destination = @q_string.split('-').last.strip
elsif @q_string.last == "-"
@origin = @q_string.split('-').first.strip
else
@origin = @q_string.split('-').first.strip
@destination = @q_string.split('-').last.strip
end
else
@includes = ['lanes','bids']
@origin = @q_string
@destination = @q_string
end
{ :objects => @includes.first, :origin => @origin, :destination => @destination }
end
def build_query()
@query = Array.new
if @origin and @destination
@query << "Location.find( :all, :origin => '#{@origin}', :include => [:lane => [:bid => [:customer]]], :within => #{@radius}, :conditions => ['mode=?',0])"
@query << "Location.find( :all, :origin => '#{@destination}', :include => [:lane => [:bid => [:customer]]], :within => #{@radius}, :conditions => ['mode=?',1])"
elsif @origin and @destination.nil?
@query << "Location.find( :all, :origin => '#{@origin}', :include => [:lane => [:bid => [:customer]]], :within => #{@radius}, :conditions => ['mode=?',0])"
elsif @destination and @origin.nil?
@query << "Location.find( :all, :origin => '#{@destination}', :include => [:lane => [:bid => [:customer]]], :within => #{@radius}, :conditions => ['mode=?',1])"
end
return @query
end
def execute()
locations = Array.new
lanes = Array.new
bids = Array.new
@query.each {|statement| locations << eval( statement) }
locations.flatten!
if @includes.include?( 'lanes' )
locations.each do |location|
lanes << location.lane
end
end#if
if @includes.include?( 'bids' )
locations.each do |location|
bids << location.lane.bid
end # do lane
end #if
if @includes.include?('bids') and @includes.include?('lanes')
return { :lanes => lanes.uniq, :bids => bids.uniq }
end
if @includes.include?('bids') and !@includes.include?('lanes')
return { :bids => bids.uniq }
end
if !@includes.include?('bids') and @includes.include?('lanes')
return { :lanes => lanes.uniq }
end
end#def
def scope( results )
bids, lanes = nil, nil
case @scope_object.class.to_s
when "Bid"
return results if results[:lanes].nil?
lanes = results[:lanes].find_all { |l| l.bid_id == @scope_object.id }
when "Customer"
return results if results[:bids].nil?
bids = results[:bids].find_all { |l| l.customer_id == @scope_object.id }
when "NilClass"
# no object was specified so return reulst provided by execute()
return( results )
end#case
{ :bids => bids, :lanes => lanes }
end#def
end
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe "search" do
describe "filtering query parameters" do
it "should pick out bids" do
string = "bids: 66216 - california"
@seeker = Seeker.new(string)
@seeker.filter_query()
@seeker.origin.should == '66216'
@seeker.destination.should == 'california'
@seeker.includes.should == ['bids']
end
it "should pick out lanes with orig and dest defined" do
string = "lanes: 66216 - california"
@seeker = Seeker.new(string)
@seeker.filter_query()
@seeker.origin.should == '66216'
@seeker.destination.should == 'california'
@seeker.includes.should == ['lanes']
end
it "should pick out lanes with no spec" do
string = "lanes: 66216"
@seeker = Seeker.new(string)
@seeker.filter_query()
@seeker.origin.should == '66216'
@seeker.destination.should == '66216'
@seeker.includes.should == ['lanes']
end
it "should pick out lanes with dest defined" do
string = "lanes: -66216"
@seeker = Seeker.new(string)
@seeker.filter_query()
@seeker.origin.should == nil
@seeker.destination.should == '66216'
@seeker.includes.should == ['lanes']
end
it "should pick out lanes with dest defined" do
string = "lanes: 66216-"
@seeker = Seeker.new(string)
@seeker.filter_query()
@seeker.origin.should == '66216'
@seeker.destination.should == nil
@seeker.includes.should == ['lanes']
end
it "should handle request without object type" do
string = "66216 - Kansas City"
@seeker = Seeker.new(string)
@seeker.filter_query()
@seeker.origin.should == "66216"
@seeker.destination.should == "Kansas City"
@seeker.includes.should == ['lanes','bids']
end
it "should handle a request wiht one parameter" do
string = "Oklahoma"
@seeker = Seeker.new(string)
@seeker.filter_query()
@seeker.origin.should == "Oklahoma"
@seeker.destination.should == "Oklahoma"
@seeker.includes.should == ['lanes','bids']
end
it "should handle a request with only orig defined" do
string = "Oklahoma-"
@seeker = Seeker.new(string)
@seeker.filter_query()
@seeker.origin.should == "Oklahoma"
@seeker.destination.should == nil
@seeker.includes.should == ['lanes','bids']
end
it "should handle a request with only destination defined" do
string = "-Oklahoma"
@seeker = Seeker.new(string)
@seeker.filter_query()
@seeker.origin.should == nil
@seeker.destination.should == "Oklahoma"
@seeker.includes.should == ['lanes','bids']
end
it "pick out lanes" do
string = "lanes:64105-Oklahoma"
@seeker = Seeker.new(string)
@seeker.filter_query()
@seeker.origin.should == "64105"
@seeker.destination.should == "Oklahoma"
@seeker.includes.should == ['lanes']
end
end # describe filter
describe "building a find query based on the filtered result" do
it "should do something" do
@seeker = Seeker.new("66216-", 25 )
@seeker.filter_query()
result = []
result << "Location.find( :all, :origin => '66216', :include => [:lane => [:bid => [:customer]]], :within => 25, :conditions => ['mode=?',0])"
@seeker.build_query().length.should == 1
@seeker.build_query().should == result
end
it "should do something" do
@seeker = Seeker.new("-66216", 25 )
@seeker.filter_query()
result = []
result << "Location.find( :all, :origin => '66216', :include => [:lane => [:bid => [:customer]]], :within => 25, :conditions => ['mode=?',1])"
@seeker.build_query().length.should == 1
@seeker.build_query().should == result
end
it "should " do
@seeker = Seeker.new("66216-64105", 25 )
@seeker.filter_query()
result = []
result << "Location.find( :all, :origin => '66216', :include => [:lane => [:bid => [:customer]]], :within => 25, :conditions => ['mode=?',0])"
result << "Location.find( :all, :origin => '64105', :include => [:lane => [:bid => [:customer]]], :within => 25, :conditions => ['mode=?',1])"
@seeker.build_query().length.should == 2
@seeker.build_query().should == result
end
end # des building query
describe "checking the results of the queries" do
it "should find " do
@location_one = Factory( :location, :location_string => "66216", :mode => 0)
@location_two = Factory( :location, :location_string => "64105", :mode => 1)
@location_one = Factory( :location, :location_string => "Oklahoma", :mode => 0)
@location_two = Factory( :location, :location_string => "Nebraska", :mode => 1)
@location_three = Factory( :location, :location_string => "alabama", :mode => 0)
@location_four = Factory( :location, :location_string => "california", :mode => 1)
@customer = Factory( :customer )
@bid = Factory( :bid )
@lane = Factory( :lane, :origin_location => @location_one,
:destination_location => @location_two)
string = "bids: -66216"
@seeker = Seeker.new( string )
@seeker.filter_query()
@seeker.origin.should == nil
end
end
describe "execution" do
before(:each) do
@location_one = Factory( :location, :location_string => "66216", :mode => 0)
@location_two = Factory( :location, :location_string => "64105", :mode => 1)
@location_three = Factory( :location, :location_string => "new york", :mode => 0)
@location_four = Factory( :location, :location_string => "california", :mode => 1)
@location_five = Factory( :location, :location_string => "66215", :mode => 0)
@location_six = Factory( :location, :location_string => "california", :mode => 1)
@customer = Factory( :customer )
@bid = Factory( :bid , :customer => @customer )
@lane = Factory( :lane, :bid => @bid,
:origin_location => @location_one,
:destination_location => @location_two )
@lane_one = Factory( :lane, :bid => @bid,
:origin_location => @location_three,
:destination_location => @location_four )
@lane_two = Factory( :lane, :bid => @bid,
:origin_location => @location_five,
:destination_location => @location_six )
end#before
describe "executing the query and combining the results" do
it "should only return bids" do
string = "bids: -64105"
@seeker = Seeker.new( string )
@seeker.filter_query()
@seeker.build_query()
@seeker.execute()[:lanes].should eql( nil )
@seeker.execute()[:bids].length.zero?.should_not eql( true )
end
it "should only return lanes" do
string = "lanes: -64105"
@seeker = Seeker.new( string )
@seeker.filter_query()
@seeker.build_query()
@seeker.execute()[:lanes].length.zero?.should_not eql( true )
@seeker.execute()[:bids].should eql( nil )
end
it "should return lanes and bids" do
string = "newyork-California"
@seeker = Seeker.new( string )
@seeker.filter_query()
@seeker.build_query()
@seeker.execute()[:lanes].length.zero?.should_not eql( true )
@seeker.execute()[:bids].length.zero?.should_not eql( true )
end
it "should return lanes and bids" do
string = "California"
@seeker = Seeker.new( string )
@seeker.filter_query()
@seeker.build_query()
@seeker.execute()[:lanes].length.zero?.should_not eql( true )
@seeker.execute()[:bids].length.zero?.should_not eql( true )
end
end# desc
describe "returning unique resluts " do
it "should not return identical bids" do
string = "bids: Kansas City"
@seeker = Seeker.new( string, 200 )
@seeker.filter_query()
@seeker.build_query()
@seeker.execute()[:bids].length.should eql( 1 )
end
end#desc unique results
describe "scope result set based on where search is being executed" do
it "should return lanes that belong to bid when on a bid page" do
params = {}
params[:search_q] = "66216-"
results = Seeker.new( params[:search_q], 100, @bid ).run()
results[:bids].should eql( nil )
results[:lanes].length.should eql( 1 )
end
it "should return all lanes mathcing the query when no scope is defined" do
params = {}
params[:search_q] = "66216-"
results = Seeker.new( params[:search_q], 100 , nil).run()
results[:bids].length.should eql( 1 )
results[:lanes].length.should eql( 2 )
end
end
end# desc execution
end # end search
@ryandotsmith
Copy link
Author

Wow, I remember writing this code at a downtown cafe in Kansas City. I lived in brookside at the time and was co-working with Ryan Felton.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment