Created
December 14, 2011 18:05
-
-
Save robhurring/1477730 to your computer and use it in GitHub Desktop.
Revisions
-
robhurring revised this gist
Dec 6, 2012 . 1 changed file with 60 additions and 13 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,32 +1,51 @@ # Search term parser from https://gist.github.com/1477730 # Modified to allow periods (and other non-letter chars) in unquoted field values # and field names. # # Helper class to help parse out more advanced saerch terms # from a form query # # Note: all hash keys are downcased, so ID:10 == {'id' => 10} # you can also access all keys with methods e.g.: terms.id = terms['id'] = 10 # this doesn't work with query as thats reserved for the left-over pieces # # Usage: # terms = SearchTerms.new('id:10 search terms here') # => @query="search terms here", @parts={"id"=>"10"} # => terms.query = 'search terms here' # => terms['id'] = 10 # # terms = SearchTerms.new('name:"support for spaces" state:pa') # => @query="", @parts={"name"=>"support for spaces", "state"=>"pa"} # => terms.query = '' # => terms['name'] = 'support for spaces' # => terms.name = 'support for spaces' # # terms = SearchTerms.new('state:pa,nj,ca') # => @query="", @parts={"state"=>["pa","nj","ca"]} # # terms = SearchTerms.new('state:pa,nj,ca', false) # => @query="", @parts={"state"=>"pa,nj,c"} # # Useful to drive custom logic in controllers class SearchTerms attr_reader :query, :parts # regex scanner for the parser SCANNER = %r{ (?: ([\w\.]+) # look for any word ) (?: # check if it has a value attached : # find the value delimiter ( [\w,\-]+ # match any word-like values | # -or- (?:"(?:.+|[^\"])*") # match any quoted values ) )? }x # query:: this is what you want tokenized # split:: if you'd like to split values on "," then pass true def initialize(query, split = true) @@ -35,7 +54,7 @@ def initialize(query, split = true) @split = split parse_query! end def [](key) @parts[key] end @@ -44,7 +63,8 @@ def [](key) def parse_query! tmp = [] @query.scan(SCANNER).map do |key,value| if value.nil? tmp << key else @@ -53,19 +73,46 @@ def parse_query! define_metaclass_method(key){ @parts[key] } unless key == 'query' end end @query = tmp.join(' ') end def clean_value(value) return value.tr('"', '') if value.include?('"') return value.split(',') if @split && value.include?(',') return true if value == 'true' return false if value == 'false' return value.to_i if value =~ /^[1-9][0-9]*$/ value end def define_metaclass_method(method, &block) (class << self; self; end).send :define_method, method, &block end end if $0 == __FILE__ require 'test/unit' class SearchTermsTest < Test::Unit::TestCase TEST_CASES = { "simple" => ["foo","foo",{}], "simple_field" => ["one:two","",{"one" => "two"}], "quotes" => [%{foo:"quoted value"}, "", {"foo" => "quoted value"}], "term_with_period" => ["1.5","1.5",{}], "multiple_fields" => ["one:two three:four","",{"one" => "two", "three" => "four"}], "int_parse" => ["id:123","",{"id" => 123}], "int_parse_leading_letter" => ["id:a01","","id" => "a01"], "int_parse_leading_zero" => ["id:001","","id" => "001"], "mixed_fields_terms" => ["one two:three four five:six","one four",{"two" => "three", "five" => "six"}] } TEST_CASES.each do |name, (input, query, parts)| define_method("test_#{name}") do terms = SearchTerms.new(input) assert_equal query, terms.query assert_equal parts, terms.parts end end end end -
robhurring revised this gist
Jan 3, 2012 . 1 changed file with 4 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -30,10 +30,10 @@ class SearchTerms # query:: this is what you want tokenized # split:: if you'd like to split values on "," then pass true def initialize(query, split = true) @query = query @parts = {} @split = split parse_query! end def [](key) @@ -42,9 +42,9 @@ def [](key) private def parse_query! tmp = [] @query.scan(/(?:(\w+))(?::([\w,\-]+|(?:"(?:.+|[^\"])*")))?/).map do |key,value| if value.nil? tmp << key else -
robhurring revised this gist
Dec 23, 2011 . 1 changed file with 13 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -2,6 +2,8 @@ # from a form query # # Note: all hash keys are downcased, so ID:10 == {'id' => 10} # you can also access all keys with methods e.g.: terms.id = terms['id'] = 10 # this doesn't work with query as thats reserved for the left-over pieces # # Usage: # terms = SearchTerms.new('id:10 search terms here') @@ -13,6 +15,7 @@ # => @query="", @parts={"name"=>"support for spaces", "state"=>"pa"} # => terms.query = '' # => terms['name'] = 'support for spaces' # => terms.name = 'support for spaces' # # terms = SearchTerms.new('state:pa,nj,ca') # => @query="", @parts={"state"=>["pa","nj","ca"]} @@ -45,7 +48,9 @@ def parse_query!(query) if value.nil? tmp << key else key.downcase! @parts[key] = clean_value(value) define_metaclass_method(key){ @parts[key] } unless key == 'query' end end @query = tmp.join(' ') @@ -54,6 +59,13 @@ def parse_query!(query) def clean_value(value) return value.tr('"', '') if value.include?('"') return value.split(',') if @split && value.include?(',') return true if value == 'true' return false if value == 'false' return value.to_i if value =~ /^[^0]\d+$/ value end def define_metaclass_method(method, &block) (class << self; self; end).send :define_method, method, &block end end -
robhurring revised this gist
Dec 23, 2011 . 1 changed file with 16 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,16 @@ # basic usage to search users from your #index action class UsersController < ApplicationController def index if params[:q] terms = SearchTerms.new(params[:q]) if terms['id'] return redirect_to user_path(terms['id']) else @users = @users.search_by_name(terms.query) unless terms.query.blank? @users = @users.with_role(terms['role']) if terms['role'] @users = @users.registered(false) if terms['guest'] end end end end -
robhurring created this gist
Dec 14, 2011 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,59 @@ # Helper class to help parse out more advanced saerch terms # from a form query # # Note: all hash keys are downcased, so ID:10 == {'id' => 10} # # Usage: # terms = SearchTerms.new('id:10 search terms here') # => @query="search terms here", @parts={"id"=>"10"} # => terms.query = 'search terms here' # => terms['id'] = 10 # # terms = SearchTerms.new('name:"support for spaces" state:pa') # => @query="", @parts={"name"=>"support for spaces", "state"=>"pa"} # => terms.query = '' # => terms['name'] = 'support for spaces' # # terms = SearchTerms.new('state:pa,nj,ca') # => @query="", @parts={"state"=>["pa","nj","ca"]} # # terms = SearchTerms.new('state:pa,nj,ca', false) # => @query="", @parts={"state"=>"pa,nj,c"} # # Useful to drive custom logic in controllers class SearchTerms attr_reader :query, :parts # query:: this is what you want tokenized # split:: if you'd like to split values on "," then pass true def initialize(query, split = true) @query = '' @parts = {} @split = split parse_query!(query) end def [](key) @parts[key] end private def parse_query!(query) tmp = [] query.scan(/(?:(\w+))(?::([\w,\-]+|(?:"(?:.+|[^\"])*")))?/).map do |key,value| if value.nil? tmp << key else @parts[key.downcase] = clean_value(value) end end @query = tmp.join(' ') end def clean_value(value) return value.tr('"', '') if value.include?('"') return value.split(',') if @split && value.include?(',') value end end