Class: SearchEngines::SearchEngineBuilder Abstract

Inherits:
Object
  • Object
show all
Includes:
HTTParty
Defined in:
lib/dsl.rb

Overview

This class is abstract.

A class that your search engine should inherit from. This is the base class for all search engines. By default, this class provides a robust DSL you can use to craft the different pieces of your search engine that must come together to satisfy the requirements of the default #search method. However, you may redefine the #search method to suit your needs, as long as it takes a QueryBuilder as an argument and returns an array of Results. Please especially review the implementation of the #search method.

See Also:

Author:

  • Shreyan Jain

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.engine_nameObject

Returns the value of attribute engine_name.



119
120
121
# File 'lib/dsl.rb', line 119

def engine_name
  @engine_name
end

Class Method Details

.config(*args) ⇒ Struct, OpenStruct

Makes your search engine have explicit configuration options. This way, you do not have to rely on environment variables, and instead can rely on conventions in the ‘conf.lua` file. You specify the different configuration options in the first call, and then you can access them in subsequent calls, like this:

-- conf.lua
engines = {
  Bing = {
    api_key = "some_ugly_api_key"
  }
}

Examples:

SearchEngines.add :Bing do
  config :api_key # Makes the `api_key` option available
  headers "Ocp-Apim-Subscription-Key": config.api_key # Accesses the `api_key` option from `conf.lua`
 end

Parameters:

  • args (Array<Symbol>)

    The names of the configuration options.

Returns:



175
176
177
178
179
180
181
# File 'lib/dsl.rb', line 175

def config(*args)
  if args.length > 0
    @config_struct = Struct.new(*args)
  else
    (@config_struct || OpenStruct).new **(Config[:engines][engine_name.to_s].to_h)
  end
end

.endpoint(string) ⇒ Object

Defines an endpoint method that returns the given string. This is the endpoint of your search engine’s API that HTTParty will call.



115
116
117
# File 'lib/dsl.rb', line 115

def endpoint(string)
  define_method(:endpoint) { string }
end

.query(&block) ⇒ :query

Defines a method that takes a block as an argument and assigns it as the implementation of the ‘query` method.

Pass it a block that takes a QueryBuilder as an input, and returns a hash which will be encoded in the URI query string as GET params.

Examples:

SearchEngines.add :Bing do
  query do |builder|
    {
      q: CGI.escape(builder.query),
      mkt: builder.market,
      SafeSearch: builder.safesearch ? 'strict' : 'moderate',
      offset: builder.offset,
      count: builder.count
    }
  end
end

Parameters:

  • block (Proc)

    The block to be assigned as the implementation of the ‘query` method.

Returns:

  • (:query)

    (because it’s a method definition)



139
140
141
# File 'lib/dsl.rb', line 139

def query(&block)
  define_method(:query, &block)
end

.results(*results_key, &result_mapping) ⇒ Object

Specify the key of the json/xml/whatever response in which the array of results will be located.

This allows you to parse the json/xml/whatever results into a Result object.

Parameters:

  • results_key (Array)

    The name of the key in the response, which can be nested several levels deep by passing multiple arguments, in the order of nesting.

  • result_mapping (Proc)

    A block that will evaluate each item in the array and returns a Result. Evaluated in the context of a ResultMapper.

See Also:



151
152
153
154
# File 'lib/dsl.rb', line 151

def results(*results_key, &result_mapping)
  define_method(:results_key) { results_key }
  define_method(:result_mapping) { result_mapping }
end

Instance Method Details

#map_result(item) ⇒ Result

Maps a single result.

Parameters:

  • item (Hash)

    The item to map.

Returns:

  • (Result)

    The mapped result.



209
210
211
212
213
214
215
# File 'lib/dsl.rb', line 209

def map_result(item)
  if result_mapping
    ResultMapper.new(item, &result_mapping).map
  else
    raise NotImplementedError, "You must define a `result_mapping` block. Please read the docs for more info."
  end
end

#map_results(response) ⇒ Array<Result>

Maps the results of a response.

Parameters:

  • response (HTTParty::Response)

    The HTTP response from calling the defined endpoint. Should contain a ‘results` key you want to map.

Returns:

  • (Array<Result>)

    An array of mapped results if result_mapping is defined.



197
198
199
200
201
202
203
204
# File 'lib/dsl.rb', line 197

def map_results(response)
  result_data = response.dig(*results_key)
  if result_mapping
    result_data.map { |item| map_result(item) }
  else
    raise NotImplementedError, "You must define a `result_mapping` block. Please read the docs for more info."
  end
end

#search(query_builder) ⇒ Array<Result>

Searches the configured search engine with the given query. When adding your own search engine, you may redefine this, as long as it works with the appropriate types. In order to map the results, use the ‘result_mapping` block.

Parameters:

  • query_builder (QueryBuilder)

    The query builder you are searching with.

Returns:

  • (Array<Result>)

    An array of search results (depends on the search engine).



190
191
192
# File 'lib/dsl.rb', line 190

def search(query_builder)
  map_results(self.class.get(endpoint, query: query(query_builder)))
end