[SEARCH] Allow connections to elasticsearch [localhost:9200] in tests and Cucumber

NOTE: The `disable_net_connect!` call has to come *before* we load the application,
      because Tire checks for index existence on application boot, and shoots
      the entire test suite down.

      See <https://github.com/karmi/tire/issues/136> for more information.
[SEARCH] Added, that factories trigger `touch` callbacks after create

NOTE: We need to be absolutely sure the `Rubygem` instance is touched, because
      we rely on it being indexed in elasticsearch in integration tests.
[SEARCH] Added elementary Tire integration into the Rubygem model

* Added, that the Version model propagates touches to Rubygem [See: http://stackoverflow.com/a/11711477/95696]

* Added Tire ActiveRecord callbacks [See: https://github.com/karmi/tire#activemodel-integration]

* Added a simple mapping definition for Rubygem

* Added a simple `to_indexed_json` serialization for Tire

* Fixed incorrect test case in WebHookTest ("include an Authorization header"):
  1) use the `build`, not the `create` FactoryGirl strategy (to skip Tire indexing), and,
  2) use the _last_ HTTP request from WebMock registry (to skip Tire checking if the index exists)

* Fixed failing "Web Hooks" feature, using the _last_ HTTP request from WebMock registry (see above)

Import your current database with the following Rake task:

    $ bundle exec rake environment tire:import CLASS='Rubygem' FORCE=1

Check the index in your browser:

    <http://localhost:9200/development_rubygems/_search>
[SEARCH] Added the simplest possible search with elasticsearch

* Added simple query string search into SearchesController

* Recreate elasticsearch index in the SearchesController functional test setup and in the Cucumber `Before('@search')` callback

* Trigger index update in the FactoryGirl `after(:create)` callback

* Be more defensive in ApplicationHelper#short_info (in test, some gems don't have versions?)

Note: The "beer laser" => "beer_laser" Cucumber scenario fails,
      due to incorrect analysis of Gem names with underscore.
[SEARCH] Added proper analyzer for Rubygem names

With the original (standard) analyzer, a Gem name like "url_mount" would be analyzed as "url_mount",
making searches for "url mount" (without the underscore) fail.

With the new analyzer, *tokens* are split by "special characters" defined by the `Patterns` module (.-_).

Try it out yourself:

  <http://localhost:9200/development_rubygems/_analyze?text=url_mount&field=name>

This change makes the "beer laser" => "beer_laser" Cucumber scenario pass.
[SEARCH] Changed the search definition to a DSL-based syntax, added sorting by downloads

* Used the DSL notation for defining the search: using a `match` prefix query on the "name" field,
  basically replicating the simple query string search with wildcards with a more performant version,
  and using a filter on the `indexed` property

* Added sorting of the results by downloads (descending)

* Added a Cucumber scenario for showing the more downloaded gems higher in search results

* Added supporting Cucumber code: a "I have a gem with downloads" and "I see these search results" step definitions
[SEARCH] Changed, that search results are ordered first by downloads, then alphabetically

* Changed the `name` property to multi-field, using the "keyword" analyzer on `name.raw` for searching
* Added the sort block with multiple sort fields
* Added a Cucumber scenario

NOTE: Now we should really stop and think twice about how to make the results more relevant.
      We should be able to get better search _precision_ by using the `Rubygem#downloads`
      counter as a factor affecting score, not just plainly sort on its value.
[SEARCH] Added a more complex mapping definition and serialization for the Rubygem model

* Previously, only the `name`, `downloads` and `indexed` attributes were indexed,
  replicating the functionality of the current search feature.

* The `to_indexed_json` method was removed, relying on Tire's JSON serialization routines
  based on the model mapping definition.

* The `summary`, `description` and `author` gem properties were added, allowing much better
  search results _recall_, ie. allowing search in these fields as well and widening the search “net”.

* A gem which mentions "sinatra" in it's summary/description will now be matched (with a lower score):
  <http://localhost:3000/search?query=sinatra>.

* A gem written by Florian Hanke will now be matched: http://localhost:3000/search?query=florian+hanke

* The `version` gem property was added, allowing searches based on gem versions, for instance looking
  for Sinatra 1.3.2: <http://localhost:3000/search?query=name:sinatra+version:1.3.2>. For improved
  usability, the link from the result listing _should_ lead to the relevant version page,
  ie. http://localhost:3000/gems/sinatra/versions/1.3.2, not the last version.

* The `depends` and `uses` gem properties were added, which index runtime gem dependencies and all
  gem dependencies, respectively. It allows searches such as <http://localhost:3000/search?query=depends:rack>
  (for gems with depend on rack) or http://localhost:3000/search?query=uses:rack (for gems which use rack in
  one way or other).

* The `created_at` and `updated_at` gem properties were added, which allow to search gems updated in a specific
  period, for instance on August, 26th: <http://localhost:3000/search?query=updated_at:[2012-08-26+TO+2012-08-27]>

* The `author`, `created_at` and `updated_at` also allow for a _faceted navigation_ in the future, ie. searching
  for certain gem while restricting the result to certain author or time.

* These properties also allow for computing statistics on the Rubygem collection, such as displaying authors
  with most gems, or authors of the most downloaded gems, etc.

You have to reindex the elasticsearch index, to pick up the new mapping and index records properly:

    $ bundle exec rake environment tire:import CLASS='Rubygem' FORCE=1

See the following resources for information on previous efforts to implement a better Rubygems.org search:

* https://groups.google.com/forum/#!topic/gemcutter/xIzyTmFdXVo/discussion
* http://florianhanke.com/blog/2011/02/13/a-better-rubygems-search.html
* http://blog.websolr.com/post/3505941785/rubygems-search-upgrade-2
* http://blog.websolr.com/post/3505969969/rubygems-search-upgrade-3
[SEARCH] Added a more complex search query in the SearchesController#show method

Previously, we have been searching gems based on their names only.

With the new, more complex mapping defined in the preceding commit, we can add a more complex search query as well.

We're using a boolean query, keeping the original match prefix query and adding the `query_string` query,
which uses the Lucene query syntax (field specifation, boolean operators, wildcards,
fuzzy search, range and proximity searches, grouping, etc).

See:

* http://www.elasticsearch.org/guide/reference/query-dsl/query-string-query.html
* http://lucene.apache.org/core/3_6_1/queryparsersyntax.html
[SEARCH] Added a `rescue_from` failed search requests due to incorrect query syntax

While we exposed the most powerful way of searching to the user (the Lucene query syntax),
it can quite easily lead to application errors when users enter incorrect queries, such as `bang!` or `foo[]`.

Since this is an error on the user's part, and not the application part, we should display a friendly
error explanation and give the user a chance to correct the query.
[SEARCH] Added a "user enters a search query with incorrect syntax" Cucumber scenario

Since the application uses Cucumber scenarios for validating its proper operation,
a scenario with user entering an incorrect search query ("bang!") has been added.
[SEARCH] Added the "Search Advanced" Cucumber feature

With the complex queries now available to users of the application, we should add
acceptance tests for the common scenarios.

We'll start with searching in summaries and descriptions (thanks to the `_all` field
automatically generated by elasticsearch).

Use this command to run all search features:

    $ bundle exec cucumber --tag @search

Use this command to run the "advanced search" feature:

    $ bundle exec cucumber features/search_advanced.feature
[SEARCH] Added a Cucumber scenario for searching in gem authors

    Given we now have a more complex search available
    When we search in the `author` field
    We should get some relevant results

* Added a "Searching in authors" scenario
* Added a step for creating more complex Rubygem records into the `gem_steps.rb` definition file

Use this command to run the scenario:

    $ bundle exec cucumber --name "Searching in authors" features/search_advanced.feature
[SEARCH] Refactored the search steps to a higher-level nested step "I search for ..."

Instead of repeating the low-level steps:

    When I go to the homepage
    And I fill in "query" with "<query>"
    And I press "Search"

over and over in our scenarios, we will abstract these steps to a single step:

    When I search for "<query>"

The obvious benefit is less code duplication and more readable steps.
[SEARCH] Added "search tips" sliding panel at the search results page

* Added a second form with `query` input, to duplicate the query for easier correction/change
  at the results page

* Added a HTML partial with concrete, interactive examples of queries possible with Lucene,
  hidden by default

* Added a link and JavaScript code to toggle the sliding panel with search examples

* Added CSS styling for the new elements, added a "help.png" icon from the FamFamFam suite
[SEARCH] Prevent indexing errors on Rubygem records without a version
[SEARCH] Added starting of "elasticsearch" in the Travis CI configuration
[SEARCH] Added information about installing Elasticsearch into "Contribution Guidelines"
[SEARCH] Handle search engine being not available in user-friendly way
[SEARCH] Changed, that errors when indexing to Elasticsearch are rescued

Previously, when an error occurred while saving the model into the Elasticsearch index,
the whole operation failed and an Exception has been raised.

This patch adds a `rescue` clause which logs the exception and swallows it.