require 'cgi' module Evrythng # Wrapper for the Evrythng Search API class Search < API include Enumerable # @private attr_reader :query # Creates a new search # # @example Initialize an Evrythng search # search = Evrythng::Search.new def initialize(*) clear super end # Clears all query filters and cached results # # @return [Evrythng::Search] self # @example Clear a search for "evrythng" # search = Evrythng::Search.new # search.containing("bike").fetch # search.clear # search.fetch_next_page #=> 403 Forbidden: You must enter a query. def clear @cache = nil @query = {} @query[:q] = [] self end # @group Generic filters # Search query # # @param query [String] The search query. # @return [Evrythng::Search] self # @example Return an array of thngs containing "bike" # Evrythng::Search.new.containing("bike").fetch def containing(query) @query[:q] << query self end # Negative search query # # @param query [String] The negative search query. # @return [Evrythng::Search] self # @example Return an array of thngs containing "bike" but not "mountain" # Evrythng::Search.new.containing("bike").not_containing("mountain").fetch def not_containing(query) @query[:q] << "-#{query}" self end # Only include thngs from users in a given radius of a given location # # @param lat [Float] A latitude. # @param long [Float] A longitude. # @param radius [String] A search radius, specified in either 'mi' (miles) or 'km' (kilometers). # @return [Evrythng::Search] self # @example Return an array of thngs within a 1-kilometer radius of Barcelona # Evrythng::Search.new.containing("bike").geocode(41.38, 2.18, "1km").fetch def geocode(lat, long, radius) @query[:geocode] = [lat, long, radius].join(",") self end # @group User filters # Only include thngs owned by a given user, specified by screen_name # # @param screen_name [String] A Evrythng user name. # @return [Evrythng::Search] self # @example Return an array of thngs containing "bike" from "mike" # Evrythng::Search.new.containing("bike").from("mike").fetch def from(screen_name) @query[:q] << "from:#{screen_name}" self end # Exclude thngs from a given user, specified by screen_name # # @param screen_name [String] A Evrythng user name. # @return [Evrythng::Search] self # @example Return an array of thngs containing "bike" from everyone except "mike" # Evrythng::Search.new.containing("bike").not_from("mike").fetch def not_from(screen_name) @query[:q] << "-from:#{screen_name}" self end # @group Paging # Specify the number of thngs to return per page # # @param number [Integer] The number of thngs to return per page, up to a max of 100. # @return [Evrythng::Search] self # @example Return an array of 100 thngs containing "bike" # Evrythng::Search.new.containing("bike").per_page(100).fetch def per_page(number=15) @query[:per_page] = number self end # Specify the page number to return, up to a maximum of roughly 500 results # # @param number [Integer] The page number (starting at 1) to return, up to a max of roughly 500 results (based on {Evrythng::Client::Search#per_page} * {Evrythng::Client::Search#page}). # @return [Evrythng::Search] self # @example Return the second page of thngs containing "bike" # Evrythng::Search.new.containing("bike").page(2).fetch def page(number) @query[:page] = number self end # Indicates if there are additional results to be fetched # # @return [Boolean] # @example # search = Evrythng::Search.new.containing("bike").fetch # search.next_page? #=> true def next_page? fetch if @cache.nil? !!@cache["next_page"] end # @group Fetching # Fetch the next page of results of the query # # @return [Array] Thngs that match specified query. # @example Return the first two pages of results # search = Evrythng::Search.new.containing("bike").fetch # search.fetch_next_page def fetch_next_page if next_page? @cache = get("search", CGI.parse(@cache["next_page"][1..-1]), :json) @cache.results end end # Fetch the results of the query # # @param force [Boolean] Ignore the cache and hit the API again. # @return [Array] Thngs that match specified query. # @example Return an array of thngs containing "bike" # search = Evrythng::Search.new.containing("bike").fetch def fetch(force=false) if @cache.nil? || force options = query.dup options[:q] = options[:q].join(" ") @cache = get("search", options, :json) end @cache.results end # Calls block once for each element in self, passing that element as a parameter # # @yieldparam [Hashie::Mash] result Thngs that matches specified query. # @return [Array] Thngs that match specified query. # @example # Evrythng::Search.new.containing('cafe del mar').each do |result| # puts "#{result.identifier} by #{result.owner}" # end def each fetch.each{|result| yield result} end end end