From c4cde5101957a38693cb767e781240b9d851e935 Mon Sep 17 00:00:00 2001 From: Braulio Bhavamitra Date: Thu, 22 Dec 2011 00:34:12 +0000 Subject: [PATCH] Revert "Revert "Merge branch 'merge-requests/25'"" --- HACKING | 3 +++ INSTALL | 13 ++++++++++--- Rakefile | 2 ++ app/controllers/public/browse_controller.rb | 10 ++++++---- app/controllers/public/profile_search_controller.rb | 3 +-- app/controllers/public/search_controller.rb | 10 +++++++--- app/helpers/application_helper.rb | 2 +- app/helpers/search_helper.rb | 9 --------- app/models/article.rb | 2 +- app/models/category_finder.rb | 6 ++++-- app/models/enterprise.rb | 2 +- app/models/environment_finder.rb | 16 ++++++++++++---- app/models/region.rb | 5 ++--- config/environments/cucumber.rb | 1 - config/solr.yml.dist | 3 +++ debian/control | 2 +- debian/ferret_server.yml | 4 ---- debian/noosfero.install | 2 +- debian/noosfero.links | 2 +- debian/solr.yml | 9 +++++++++ etc/init.d/noosfero | 21 ++++++++++++++------- features/browse.feature | 1 + features/profile_search.feature | 3 ++- features/search.feature | 3 +++ features/step_definitions/noosfero_steps.rb | 4 ++++ lib/acts_as_searchable.rb | 72 +++++++++++++++++++++++++++++++++++++++++------------------------------- lib/create_thumbnails_job.rb | 2 -- lib/tasks/cucumber.rake | 17 +++++++++++++++-- lib/tasks/package.rake | 12 ++++++++++++ lib/tasks/test.rake | 5 +++++ script/development | 5 +++++ script/ferret_server | 10 ---------- script/production | 4 ++-- test/factories.rb | 2 +- test/functional/browse_controller_test.rb | 1 + test/functional/profile_members_controller_test.rb | 1 + test/functional/profile_search_controller_test.rb | 13 +++---------- test/functional/search_controller_test.rb | 16 +--------------- test/test_helper.rb | 20 +++++--------------- test/unit/article_test.rb | 23 ++++++++++++----------- test/unit/category_finder_test.rb | 3 +++ test/unit/enterprise_test.rb | 11 +++++++++-- test/unit/environment_finder_test.rb | 5 +++-- test/unit/environment_test.rb | 8 ++++++-- test/unit/event_test.rb | 8 ++++++-- test/unit/forum_helper_test.rb | 4 ++-- test/unit/product_test.rb | 19 ++++++++++--------- test/unit/profile_test.rb | 36 ++++++++++++++++++++---------------- test/unit/tiny_mce_article_test.rb | 7 ++++--- vendor/plugins/access_control/init.rb | 2 +- vendor/plugins/access_control/lib/permission_name_helper.rb | 2 +- vendor/plugins/acts_as_ferret/LICENSE | 20 -------------------- vendor/plugins/acts_as_ferret/README | 53 ----------------------------------------------------- vendor/plugins/acts_as_ferret/bin/aaf_install | 23 ----------------------- vendor/plugins/acts_as_ferret/config/ferret_server.yml | 24 ------------------------ vendor/plugins/acts_as_ferret/doc/README.win32 | 23 ----------------------- vendor/plugins/acts_as_ferret/doc/monit-example | 22 ---------------------- vendor/plugins/acts_as_ferret/init.rb | 24 ------------------------ vendor/plugins/acts_as_ferret/install.rb | 18 ------------------ vendor/plugins/acts_as_ferret/lib/act_methods.rb | 155 ----------------------------------------------------------------------------------------------------------------------------------------------------------- vendor/plugins/acts_as_ferret/lib/acts_as_ferret.rb | 567 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- vendor/plugins/acts_as_ferret/lib/ar_mysql_auto_reconnect_patch.rb | 41 ----------------------------------------- vendor/plugins/acts_as_ferret/lib/blank_slate.rb | 53 ----------------------------------------------------- vendor/plugins/acts_as_ferret/lib/bulk_indexer.rb | 35 ----------------------------------- vendor/plugins/acts_as_ferret/lib/class_methods.rb | 295 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- vendor/plugins/acts_as_ferret/lib/ferret_extensions.rb | 115 ------------------------------------------------------------------------------------------------------------------- vendor/plugins/acts_as_ferret/lib/ferret_find_methods.rb | 118 ---------------------------------------------------------------------------------------------------------------------- vendor/plugins/acts_as_ferret/lib/ferret_result.rb | 53 ----------------------------------------------------- vendor/plugins/acts_as_ferret/lib/ferret_server.rb | 238 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- vendor/plugins/acts_as_ferret/lib/index.rb | 99 --------------------------------------------------------------------------------------------------- vendor/plugins/acts_as_ferret/lib/instance_methods.rb | 165 --------------------------------------------------------------------------------------------------------------------------------------------------------------------- vendor/plugins/acts_as_ferret/lib/local_index.rb | 199 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- vendor/plugins/acts_as_ferret/lib/more_like_this.rb | 217 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- vendor/plugins/acts_as_ferret/lib/multi_index.rb | 126 ------------------------------------------------------------------------------------------------------------------------------ vendor/plugins/acts_as_ferret/lib/rdig_adapter.rb | 141 --------------------------------------------------------------------------------------------------------------------------------------------- vendor/plugins/acts_as_ferret/lib/remote_functions.rb | 23 ----------------------- vendor/plugins/acts_as_ferret/lib/remote_index.rb | 54 ------------------------------------------------------ vendor/plugins/acts_as_ferret/lib/remote_multi_index.rb | 20 -------------------- vendor/plugins/acts_as_ferret/lib/search_results.rb | 50 -------------------------------------------------- vendor/plugins/acts_as_ferret/lib/server_manager.rb | 58 ---------------------------------------------------------- vendor/plugins/acts_as_ferret/lib/unix_daemon.rb | 64 ---------------------------------------------------------------- vendor/plugins/acts_as_ferret/lib/without_ar.rb | 49 ------------------------------------------------- vendor/plugins/acts_as_ferret/rakefile | 134 -------------------------------------------------------------------------------------------------------------------------------------- vendor/plugins/acts_as_ferret/recipes/aaf_recipes.rb | 97 ------------------------------------------------------------------------------------------------- vendor/plugins/acts_as_ferret/script/ferret_daemon | 94 ---------------------------------------------------------------------------------------------- vendor/plugins/acts_as_ferret/script/ferret_server | 10 ---------- vendor/plugins/acts_as_ferret/script/ferret_service | 178 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- vendor/plugins/acts_as_ferret/tasks/ferret.rake | 24 ------------------------ vendor/plugins/acts_as_solr_reloaded/.gitignore | 17 +++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/LICENSE | 22 ++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/README.markdown | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/README.rdoc | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/Rakefile | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/TESTING_THE_PLUGIN | 25 +++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/VERSION | 1 + vendor/plugins/acts_as_solr_reloaded/acts_as_solr_reloaded.gemspec | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/config/solr.yml | 14 ++++++++++++++ vendor/plugins/acts_as_solr_reloaded/config/solr_environment.rb | 43 +++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/generators/dynamic_attributes_migration/dynamic_attributes_migration_generator.rb | 7 +++++++ vendor/plugins/acts_as_solr_reloaded/generators/dynamic_attributes_migration/templates/migration.rb | 17 +++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/generators/local_migration/local_migration_generator.rb | 7 +++++++ vendor/plugins/acts_as_solr_reloaded/generators/local_migration/templates/migration.rb | 16 ++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/init.rb | 1 + vendor/plugins/acts_as_solr_reloaded/install.rb | 5 +++++ vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr.rb | 47 +++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/acts_methods.rb | 373 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/class_methods.rb | 242 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/common_methods.rb | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/deprecation.rb | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/dynamic_attribute.rb | 3 +++ vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/instance_methods.rb | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/lazy_document.rb | 18 ++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/local.rb | 4 ++++ vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/mongo_mapper.rb | 27 +++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/parser_methods.rb | 260 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/search_results.rb | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/solr_fixtures.rb | 13 +++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/tasks.rb | 10 ++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr_reloaded.rb | 1 + vendor/plugins/acts_as_solr_reloaded/lib/solr.rb | 26 ++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/connection.rb | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/document.rb | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/exception.rb | 13 +++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/field.rb | 36 ++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/importer.rb | 19 +++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/array_mapper.rb | 26 ++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/delimited_file_source.rb | 38 ++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/hpricot_mapper.rb | 27 +++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/mapper.rb | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/solr_source.rb | 41 +++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/xpath_mapper.rb | 35 +++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/indexer.rb | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/request.rb | 26 ++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/request/add_document.rb | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/request/base.rb | 36 ++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/request/commit.rb | 29 +++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/request/delete.rb | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/request/dismax.rb | 46 ++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/request/index_info.rb | 22 ++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/request/modify_document.rb | 46 ++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/request/optimize.rb | 19 +++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/request/ping.rb | 36 ++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/request/select.rb | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/request/spellcheck.rb | 30 ++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/request/standard.rb | 409 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/request/update.rb | 23 +++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/response.rb | 27 +++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/response/add_document.rb | 17 +++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/response/base.rb | 42 ++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/response/commit.rb | 15 +++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/response/delete.rb | 13 +++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/response/dismax.rb | 8 ++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/response/index_info.rb | 26 ++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/response/modify_document.rb | 17 +++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/response/optimize.rb | 14 ++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/response/ping.rb | 26 ++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/response/ruby.rb | 42 ++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/response/select.rb | 17 +++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/response/spellcheck.rb | 20 ++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/response/standard.rb | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/response/xml.rb | 39 +++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/solrtasks.rb | 27 +++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/util.rb | 32 ++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/solr/xml.rb | 43 +++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/tasks/database.rake | 16 ++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/tasks/solr.rake | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/lib/tasks/test.rake | 5 +++++ vendor/plugins/acts_as_solr_reloaded/rails/init.rb | 1 + vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/admin-extra.html | 31 +++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/elevate.xml | 36 ++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/mapping-ISOLatin1Accent.txt | 246 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/protwords.txt | 21 +++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/schema.xml | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/scripts.conf | 24 ++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/solrconfig.xml | 898 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/spellings.txt | 2 ++ vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/stopwords.txt | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/synonyms.txt | 31 +++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/example.xsl | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/example_atom.xsl | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/example_rss.xsl | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/luke.xsl | 337 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/solr_test_rakefile.rb | 6 ++++++ vendor/plugins/acts_as_solr_reloaded/test/config/solr.yml | 2 ++ vendor/plugins/acts_as_solr_reloaded/test/db/connections/mysql/connection.rb | 11 +++++++++++ vendor/plugins/acts_as_solr_reloaded/test/db/connections/sqlite/connection.rb | 8 ++++++++ vendor/plugins/acts_as_solr_reloaded/test/db/migrate/001_create_books.rb | 15 +++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/db/migrate/002_create_movies.rb | 12 ++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/db/migrate/003_create_categories.rb | 11 +++++++++++ vendor/plugins/acts_as_solr_reloaded/test/db/migrate/004_create_electronics.rb | 16 ++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/db/migrate/005_create_authors.rb | 12 ++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/db/migrate/006_create_postings.rb | 9 +++++++++ vendor/plugins/acts_as_solr_reloaded/test/db/migrate/007_create_posts.rb | 13 +++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/db/migrate/008_create_gadgets.rb | 11 +++++++++++ vendor/plugins/acts_as_solr_reloaded/test/db/migrate/009_create_dynamic_attributes.rb | 15 +++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/db/migrate/010_create_advertises.rb | 13 +++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/db/migrate/011_create_locals.rb | 15 +++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/fixtures/advertises.yml | 12 ++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/fixtures/authors.yml | 9 +++++++++ vendor/plugins/acts_as_solr_reloaded/test/fixtures/books.yml | 13 +++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/fixtures/categories.yml | 7 +++++++ vendor/plugins/acts_as_solr_reloaded/test/fixtures/db_definitions/mysql.sql | 41 +++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/fixtures/dynamic_attributes.yml | 11 +++++++++++ vendor/plugins/acts_as_solr_reloaded/test/fixtures/electronics.yml | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/fixtures/locals.yml | 9 +++++++++ vendor/plugins/acts_as_solr_reloaded/test/fixtures/movies.yml | 9 +++++++++ vendor/plugins/acts_as_solr_reloaded/test/fixtures/postings.yml | 10 ++++++++++ vendor/plugins/acts_as_solr_reloaded/test/functional/acts_as_solr_test.rb | 501 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/functional/association_indexing_test.rb | 37 +++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/functional/faceted_search_test.rb | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/functional/multi_solr_search_test.rb | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/models/advertise.rb | 6 ++++++ vendor/plugins/acts_as_solr_reloaded/test/models/author.rb | 10 ++++++++++ vendor/plugins/acts_as_solr_reloaded/test/models/book.rb | 10 ++++++++++ vendor/plugins/acts_as_solr_reloaded/test/models/category.rb | 8 ++++++++ vendor/plugins/acts_as_solr_reloaded/test/models/document.rb | 6 ++++++ vendor/plugins/acts_as_solr_reloaded/test/models/dynamic_attribute.rb | 7 +++++++ vendor/plugins/acts_as_solr_reloaded/test/models/electronic.rb | 25 +++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/models/gadget.rb | 9 +++++++++ vendor/plugins/acts_as_solr_reloaded/test/models/local.rb | 7 +++++++ vendor/plugins/acts_as_solr_reloaded/test/models/movie.rb | 17 +++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/models/novel.rb | 2 ++ vendor/plugins/acts_as_solr_reloaded/test/models/post.rb | 3 +++ vendor/plugins/acts_as_solr_reloaded/test/models/posting.rb | 11 +++++++++++ vendor/plugins/acts_as_solr_reloaded/test/test_helper.rb | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/unit/acts_methods_shoulda.rb | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/unit/class_methods_shoulda.rb | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/unit/common_methods_shoulda.rb | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/unit/instance_methods_shoulda.rb | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/unit/lazy_document_shoulda.rb | 34 ++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/unit/parser_instance.rb | 19 +++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/unit/parser_methods_shoulda.rb | 352 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/unit/solr_instance.rb | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vendor/plugins/acts_as_solr_reloaded/test/unit/test_helper.rb | 30 ++++++++++++++++++++++++++++++ 234 files changed, 9071 insertions(+), 3867 deletions(-) delete mode 100644 debian/ferret_server.yml create mode 100644 debian/solr.yml delete mode 100755 script/ferret_server delete mode 100644 vendor/plugins/acts_as_ferret/LICENSE delete mode 100644 vendor/plugins/acts_as_ferret/README delete mode 100644 vendor/plugins/acts_as_ferret/bin/aaf_install delete mode 100644 vendor/plugins/acts_as_ferret/config/ferret_server.yml delete mode 100644 vendor/plugins/acts_as_ferret/doc/README.win32 delete mode 100644 vendor/plugins/acts_as_ferret/doc/monit-example delete mode 100644 vendor/plugins/acts_as_ferret/init.rb delete mode 100644 vendor/plugins/acts_as_ferret/install.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/act_methods.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/acts_as_ferret.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/ar_mysql_auto_reconnect_patch.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/blank_slate.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/bulk_indexer.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/class_methods.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/ferret_extensions.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/ferret_find_methods.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/ferret_result.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/ferret_server.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/index.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/instance_methods.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/local_index.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/more_like_this.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/multi_index.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/rdig_adapter.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/remote_functions.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/remote_index.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/remote_multi_index.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/search_results.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/server_manager.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/unix_daemon.rb delete mode 100644 vendor/plugins/acts_as_ferret/lib/without_ar.rb delete mode 100644 vendor/plugins/acts_as_ferret/rakefile delete mode 100644 vendor/plugins/acts_as_ferret/recipes/aaf_recipes.rb delete mode 100644 vendor/plugins/acts_as_ferret/script/ferret_daemon delete mode 100644 vendor/plugins/acts_as_ferret/script/ferret_server delete mode 100644 vendor/plugins/acts_as_ferret/script/ferret_service delete mode 100644 vendor/plugins/acts_as_ferret/tasks/ferret.rake create mode 100644 vendor/plugins/acts_as_solr_reloaded/.gitignore create mode 100644 vendor/plugins/acts_as_solr_reloaded/LICENSE create mode 100644 vendor/plugins/acts_as_solr_reloaded/README.markdown create mode 100644 vendor/plugins/acts_as_solr_reloaded/README.rdoc create mode 100644 vendor/plugins/acts_as_solr_reloaded/Rakefile create mode 100644 vendor/plugins/acts_as_solr_reloaded/TESTING_THE_PLUGIN create mode 100644 vendor/plugins/acts_as_solr_reloaded/VERSION create mode 100644 vendor/plugins/acts_as_solr_reloaded/acts_as_solr_reloaded.gemspec create mode 100644 vendor/plugins/acts_as_solr_reloaded/config/solr.yml create mode 100644 vendor/plugins/acts_as_solr_reloaded/config/solr_environment.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/generators/dynamic_attributes_migration/dynamic_attributes_migration_generator.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/generators/dynamic_attributes_migration/templates/migration.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/generators/local_migration/local_migration_generator.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/generators/local_migration/templates/migration.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/init.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/install.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/acts_methods.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/class_methods.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/common_methods.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/deprecation.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/dynamic_attribute.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/instance_methods.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/lazy_document.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/local.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/mongo_mapper.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/parser_methods.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/search_results.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/solr_fixtures.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/tasks.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr_reloaded.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/connection.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/document.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/exception.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/field.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/importer.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/array_mapper.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/delimited_file_source.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/hpricot_mapper.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/mapper.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/solr_source.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/xpath_mapper.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/indexer.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/request.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/request/add_document.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/request/base.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/request/commit.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/request/delete.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/request/dismax.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/request/index_info.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/request/modify_document.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/request/optimize.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/request/ping.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/request/select.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/request/spellcheck.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/request/standard.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/request/update.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/response.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/response/add_document.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/response/base.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/response/commit.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/response/delete.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/response/dismax.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/response/index_info.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/response/modify_document.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/response/optimize.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/response/ping.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/response/ruby.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/response/select.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/response/spellcheck.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/response/standard.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/response/xml.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/solrtasks.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/lib/solr/util.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/solr/xml.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/tasks/database.rake create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/tasks/solr.rake create mode 100644 vendor/plugins/acts_as_solr_reloaded/lib/tasks/test.rake create mode 100644 vendor/plugins/acts_as_solr_reloaded/rails/init.rb create mode 100755 vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/admin-extra.html create mode 100755 vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/elevate.xml create mode 100755 vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/mapping-ISOLatin1Accent.txt create mode 100755 vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/protwords.txt create mode 100755 vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/schema.xml create mode 100755 vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/scripts.conf create mode 100755 vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/solrconfig.xml create mode 100755 vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/spellings.txt create mode 100755 vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/stopwords.txt create mode 100755 vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/synonyms.txt create mode 100755 vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/example.xsl create mode 100755 vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/example_atom.xsl create mode 100755 vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/example_rss.xsl create mode 100755 vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/luke.xsl create mode 100644 vendor/plugins/acts_as_solr_reloaded/solr_test_rakefile.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/config/solr.yml create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/db/connections/mysql/connection.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/db/connections/sqlite/connection.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/db/migrate/001_create_books.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/db/migrate/002_create_movies.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/db/migrate/003_create_categories.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/db/migrate/004_create_electronics.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/db/migrate/005_create_authors.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/db/migrate/006_create_postings.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/db/migrate/007_create_posts.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/db/migrate/008_create_gadgets.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/db/migrate/009_create_dynamic_attributes.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/db/migrate/010_create_advertises.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/db/migrate/011_create_locals.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/fixtures/advertises.yml create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/fixtures/authors.yml create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/fixtures/books.yml create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/fixtures/categories.yml create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/fixtures/db_definitions/mysql.sql create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/fixtures/dynamic_attributes.yml create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/fixtures/electronics.yml create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/fixtures/locals.yml create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/fixtures/movies.yml create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/fixtures/postings.yml create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/functional/acts_as_solr_test.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/functional/association_indexing_test.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/functional/faceted_search_test.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/functional/multi_solr_search_test.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/models/advertise.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/models/author.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/models/book.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/models/category.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/models/document.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/models/dynamic_attribute.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/models/electronic.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/models/gadget.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/models/local.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/models/movie.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/models/novel.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/models/post.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/models/posting.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/test_helper.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/unit/acts_methods_shoulda.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/unit/class_methods_shoulda.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/unit/common_methods_shoulda.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/unit/instance_methods_shoulda.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/unit/lazy_document_shoulda.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/unit/parser_instance.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/unit/parser_methods_shoulda.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/unit/solr_instance.rb create mode 100644 vendor/plugins/acts_as_solr_reloaded/test/unit/test_helper.rb diff --git a/HACKING b/HACKING index 065e648..bdbf8a0 100644 --- a/HACKING +++ b/HACKING @@ -40,6 +40,9 @@ commands and make sure you understand what you are doing): cp config/database.yml.sqlite3 config/database.yml # create tmp directory if it doesn't exist mkdir tmp + # download and start Solr + rake solr:download + rake solr:start # create the development database rake db:schema:load # run pending migrations diff --git a/INSTALL b/INSTALL index b98392f..dd2ea2d 100644 --- a/INSTALL +++ b/INSTALL @@ -13,7 +13,7 @@ You need to install some packages Noosfero depends on. On Debian GNU/Linux or Debian-based systems, all of these packages are available through the Debian archive. You can install them with the following command: - # apt-get install ruby rake po4a libgettext-ruby-util libgettext-ruby-data libgettext-ruby1.8 libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby libwill-paginate-ruby iso-codes libfeedparser-ruby libferret-ruby libdaemons-ruby mongrel mongrel-cluster tango-icon-theme libhpricot-ruby + # apt-get install ruby rake po4a libgettext-ruby-util libgettext-ruby-data libgettext-ruby1.8 libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby libwill-paginate-ruby iso-codes libfeedparser-ruby openjdk-6-jre libdaemons-ruby mongrel mongrel-cluster tango-icon-theme libhpricot-ruby On other systems, they may or may not be available through your regular package management system. Below are the links to their homepages. @@ -24,7 +24,7 @@ management system. Below are the links to their homepages. * Ruby-GetText: http://www.yotabanana.com/hiki/ruby-gettext.html?ruby-gettext (at least version 1.9.0) * Ruby-sqlite3: http://rubyforge.org/projects/sqlite-ruby * rcov: http://eigenclass.org/hiki/rcov -* Ferret: http://ferret.davebalmain.com/trac +* Solr: http://lucene.apache.org/solr * RMagick: http://rmagick.rubyforge.org/ * RedCloth: http://redcloth.org/ * will_paginate: http://github.com/mislav/will_paginate/wikis @@ -115,8 +115,11 @@ $ tar -zxvf noosfero-0.27.1.tar.gz $ ln -s noosfero-0.27.1 current $ cd current -Copy config/ferret_server.yml.dist to config/ferret_server.yml. You will +Copy config/solr.yml.dist to config/solr.yml. You will probably not need to customize this configuration, but have a look at it. +Then you'll need to download Solr into noosfero: + +$ rake solr:download Create the mongrel configuration file: @@ -237,6 +240,10 @@ Create the database structure: $ RAILS_ENV=production rake db:schema:load +Run Solr: + +$ rake solr:start + Now we have to create some initial data. To create your default environment (the first one), run the command below: diff --git a/Rakefile b/Rakefile index 3bb0e85..6d7ea85 100644 --- a/Rakefile +++ b/Rakefile @@ -7,4 +7,6 @@ require 'rake' require 'rake/testtask' require 'rake/rdoctask' +ACTS_AS_SEARCHABLE_ENABLED = false if Rake.application.top_level_tasks.detect{|t| t == 'db:data:minimal'} + require 'tasks/rails' diff --git a/app/controllers/public/browse_controller.rb b/app/controllers/public/browse_controller.rb index f37c68f..079a5ac 100644 --- a/app/controllers/public/browse_controller.rb +++ b/app/controllers/public/browse_controller.rb @@ -21,9 +21,10 @@ class BrowseController < PublicController @results = @environment.people.visible.send(@filter) if !params[:query].blank? - @results = @results.find_by_contents(params[:query]) + @results = @results.find_by_contents(params[:query], {:per_page => per_page, :page => params[:page]})[:results] + else + @results = @results.compact.paginate(:per_page => per_page, :page => params[:page]) end - @results = @results.compact.paginate(:per_page => per_page, :page => params[:page]) end def communities @@ -33,9 +34,10 @@ class BrowseController < PublicController @results = @environment.communities.visible.send(@filter) if !params[:query].blank? - @results = @results.find_by_contents(params[:query]) + @results = @results.find_by_contents(params[:query], {:per_page => per_page, :page => params[:page]})[:results] + else + @results = @results.compact.paginate(:per_page => per_page, :page => params[:page]) end - @results = @results.compact.paginate(:per_page => per_page, :page => params[:page]) end def contents diff --git a/app/controllers/public/profile_search_controller.rb b/app/controllers/public/profile_search_controller.rb index 4bf9075..78bd38b 100644 --- a/app/controllers/public/profile_search_controller.rb +++ b/app/controllers/public/profile_search_controller.rb @@ -8,11 +8,10 @@ class ProfileSearchController < PublicController def index @q = params[:q] unless @q.blank? - @filtered_query = remove_stop_words(@q) if params[:where] == 'environment' redirect_to :controller => 'search', :query => @q else - @results = profile.articles.published.find_by_contents(@filtered_query).paginate(:per_page => 10, :page => params[:page]) + @results = Article.find_by_contents(@q + " profile_id:#{profile.id} published:true")[:results].paginate(:per_page => 10, :page => params[:page]) end end end diff --git a/app/controllers/public/search_controller.rb b/app/controllers/public/search_controller.rb index 094ae07..7cd6082 100644 --- a/app/controllers/public/search_controller.rb +++ b/app/controllers/public/search_controller.rb @@ -89,7 +89,8 @@ class SearchController < PublicController # REFACTOR DUPLICATED CODE inner loop doing the same thing that outter loop if !@query.blank? || @region && !params[:radius].blank? - @result_ids = @noosfero_finder.find(asset, @filtered_query, calculate_find_options(asset, nil, params[:page], @product_category, @region, params[:radius], params[:year], params[:month]).merge({:limit => :all})) + ret = @noosfero_finder.find(asset, @query, calculate_find_options(asset, nil, params[:page], @product_category, @region, params[:radius], params[:year], params[:month]).merge({:limit => :all})) + @result_ids = ret.is_a?(Hash) ? ret[:results] : ret end end @@ -149,7 +150,6 @@ class SearchController < PublicController def index @query = params[:query] || '' - @filtered_query = remove_stop_words(@query) @product_category = ProductCategory.find(params[:product_category]) if params[:product_category] @region = City.find_by_id(params[:city]) if !params[:city].blank? && params[:city] =~ /^\d+$/ @@ -158,12 +158,16 @@ class SearchController < PublicController number_of_result_assets = @searching.values.select{|v| v}.size @results = {} + @facets = {} @order = [] @names = {} where_to_search.select { |key,description| @searching[key] }.each do |key, description| @order << key - @results[key] = @noosfero_finder.find(key, @filtered_query, calculate_find_options(key, limit, params[:page], @product_category, @region, params[:radius], params[:year], params[:month])) + find_options = calculate_find_options(key, limit, params[:page], @product_category, @region, params[:radius], params[:year], params[:month]); + ret = @noosfero_finder.find(key, @query, find_options) + @results[key] = ret.is_a?(Hash) ? ret[:results] : ret + @facets[key] = ret.is_a?(Hash) ? ret[:facets] : {} @names[key] = getterm(description) end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 3d9121b..bfe6bba 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -2,7 +2,7 @@ # application. module ApplicationHelper - include PermissionName + include PermissionNameHelper include LightboxHelper diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index c1f6fde..3ba9ae1 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -3,21 +3,12 @@ module SearchHelper # FIXME remove it after search_controler refactored include EventsHelper - STOP_WORDS = { - 'pt_BR' => Ferret::Analysis::FULL_PORTUGUESE_STOP_WORDS, - 'en' => Ferret::Analysis::FULL_ENGLISH_STOP_WORDS, - } - def relevance_for(hit) n = (hit.ferret_score if hit.respond_to?(:ferret_score)) n ||= 1.0 (n * 100.0).round end - def remove_stop_words(query) - (query.downcase.scan(/"[^"]*"?|'[^']*'?|[^'"\s]+/) - (STOP_WORDS[locale] || [])).join(' ') - end - def display_results(use_map = true) unless use_map && GoogleMaps.enabled?(environment.default_hostname) diff --git a/app/models/article.rb b/app/models/article.rb index f5956a2..aaa2b5c 100644 --- a/app/models/article.rb +++ b/app/models/article.rb @@ -409,7 +409,7 @@ class Article < ActiveRecord::Base end def comments_updated - ferret_update + solr_save end def accept_category?(cat) diff --git a/app/models/category_finder.rb b/app/models/category_finder.rb index 1a5b802..2907ce8 100644 --- a/app/models/category_finder.rb +++ b/app/models/category_finder.rb @@ -28,10 +28,12 @@ class CategoryFinder end if query.blank? + options.delete(:facets) asset_class(asset).send(finder_method, :all, options_for_find(asset_class(asset), {:order => "#{asset_table(asset)}.name"}.merge(options), date_range)) else - ferret_options = {:page => options.delete(:page), :per_page => options.delete(:per_page)} - asset_class(asset).find_by_contents(query, ferret_options, options_for_find(asset_class(asset), options, date_range)) + pg_options = {:page => options.delete(:page), :per_page => options.delete(:per_page)} + solr_options = {:facets => options.delete(:facets)} + asset_class(asset).find_by_contents(query, pg_options, solr_options, options_for_find(asset_class(asset), options, date_range))[:results] end end diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index d7b9f96..280aba9 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -71,7 +71,7 @@ class Enterprise < Organization end def product_updated - ferret_update + solr_save end after_save do |e| diff --git a/app/models/environment_finder.rb b/app/models/environment_finder.rb index 17050fd..f046969 100644 --- a/app/models/environment_finder.rb +++ b/app/models/environment_finder.rb @@ -22,6 +22,8 @@ class EnvironmentFinder end if query.blank? + options.delete(:facets) + # FIXME this test is in more than one place if finder_method == 'paginate' options = {:order => "#{asset_table(asset)}.name"}.merge(options) @@ -48,14 +50,20 @@ class EnvironmentFinder end end else - ferret_options = {:page => options.delete(:page), :per_page => options.delete(:per_page)} + pg_options = {:page => options.delete(:page), :per_page => options.delete(:per_page)} + solr_options = {:facets => options.delete(:facets)} if product_category && asset == :products # SECURITY no risk of SQL injection, since product_category_ids comes from trusted source - @environment.send(asset).find_by_contents(query, ferret_options, options.merge({:include => 'product_categorizations', :conditions => 'product_categorizations.category_id = (%s)' % product_category.id })) + ret = @environment.send(asset).find_by_contents(query, pg_options, solr_options, options.merge({:include => 'product_categorizations', :conditions => 'product_categorizations.category_id = (%s)' % product_category.id })) elsif product_category && asset == :enterprises - @environment.send(asset).find_by_contents(query, ferret_options, options.merge(:joins => 'inner join product_categorizations on (product_categorizations.product_id = products.id)', :include => 'products', :conditions => "product_categorizations.category_id = (#{product_category.id})")) + ret = @environment.send(asset).find_by_contents(query, pg_options, solr_options, options.merge(:joins => 'inner join product_categorizations on (product_categorizations.product_id = products.id)', :include => 'products', :conditions => "product_categorizations.category_id = (#{product_category.id})")) + else + ret = @environment.send(asset).find_by_contents(query, pg_options, solr_options, options) + end + if solr_options[:facets].nil? + ret[:results] else - @environment.send(asset).find_by_contents(query, ferret_options, options) + ret end end end diff --git a/app/models/region.rb b/app/models/region.rb index f86cb91..8e95afc 100644 --- a/app/models/region.rb +++ b/app/models/region.rb @@ -5,10 +5,9 @@ class Region < Category require_dependency 'enterprise' # enterprises can also be validators # searches for organizations that could become validators for this region. - # search is passed as is to ferret's find_by_contents on Organizatio - # find_by_contents on Organization class. + # search is passed as is to find_by_contents on Organization. def search_possible_validators(search) - Organization.find_by_contents(search).reject {|item| self.validator_ids.include?(item.id) } + Organization.find_by_contents(search)[:results].reject {|item| self.validator_ids.include?(item.id) } end def has_validator? diff --git a/config/environments/cucumber.rb b/config/environments/cucumber.rb index 80527d9..489237d 100644 --- a/config/environments/cucumber.rb +++ b/config/environments/cucumber.rb @@ -26,4 +26,3 @@ config.gem 'rspec-rails', :lib => 'spec/rails', :version => '1.2.9' unles config.gem 'Selenium', :lib => 'selenium', :version => '>= 1.1.14' unless File.directory?(File.join(Rails.root, 'vendor/plugins/selenium')) config.gem 'selenium-client', :lib => 'selenium/client', :version => '>= 1.2.17' unless File.directory?(File.join(Rails.root, 'vendor/plugins/selenium-client')) config.gem 'database_cleaner', :lib => 'database_cleaner' - diff --git a/config/solr.yml.dist b/config/solr.yml.dist index 811de24..0619b8e 100644 --- a/config/solr.yml.dist +++ b/config/solr.yml.dist @@ -15,3 +15,6 @@ test: url: http://0.0.0.0:8981/solr jvm_options: -server -Xmx32M -Xms16M +cucumber: + url: http://0.0.0.0:8980/solr + jvm_options: -server -Xmx32M -Xms16M diff --git a/debian/control b/debian/control index 3184031..cdbdd0e 100644 --- a/debian/control +++ b/debian/control @@ -11,7 +11,7 @@ Vcs-Browser: http://git.colivre.coop.br/?p=noosfero.git Package: noosfero Architecture: all -Depends: rails, ruby1.8, ruby, rake, libgettext-ruby-data, libsqlite3-ruby, libpgsql-ruby, libmysql-ruby, librmagick-ruby, libredcloth-ruby, libwill-paginate-ruby, iso-codes, libfeedparser-ruby, libferret-ruby, libdaemons-ruby, rcov, mongrel, mongrel-cluster, tango-icon-theme, libhpricot-ruby, iso-codes, memcached, debconf, dbconfig-common, postgresql, adduser, ${misc:Depends} +Depends: rails, ruby1.8, ruby, rake, libgettext-ruby-data, libsqlite3-ruby, libpgsql-ruby, libmysql-ruby, librmagick-ruby, libredcloth-ruby, libwill-paginate-ruby, iso-codes, libfeedparser-ruby, openjdk-6-jre, libdaemons-ruby, rcov, mongrel, mongrel-cluster, tango-icon-theme, libhpricot-ruby, iso-codes, memcached, debconf, dbconfig-common, postgresql, adduser, ${misc:Depends} Recommends: postgresql-client Description: free web-based platform for social networks Noosfero is a web platform for social and solidarity economy networks with diff --git a/debian/ferret_server.yml b/debian/ferret_server.yml deleted file mode 100644 index 1b2010f..0000000 --- a/debian/ferret_server.yml +++ /dev/null @@ -1,4 +0,0 @@ -production: - host: localhost - port: 51000 - pid_file: tmp/pids/ferret.production.pid diff --git a/debian/noosfero.install b/debian/noosfero.install index f51627f..a0aa8c1 100644 --- a/debian/noosfero.install +++ b/debian/noosfero.install @@ -28,7 +28,7 @@ public usr/share/noosfero debian/default/noosfero etc/default etc/init.d/noosfero etc/init.d debian/mongrel_cluster.yml etc/noosfero -debian/ferret_server.yml etc/noosfero +debian/solr.yml etc/noosfero etc/logrotate.d/noosfero etc/logrotate.d debian/noosfero.yml etc/noosfero diff --git a/debian/noosfero.links b/debian/noosfero.links index 682403a..fa6039a 100644 --- a/debian/noosfero.links +++ b/debian/noosfero.links @@ -3,7 +3,7 @@ var/tmp/noosfero usr/share/noosfero/tmp var/log/noosfero usr/share/noosfero/log etc/noosfero/database.yml usr/share/noosfero/config/database.yml etc/noosfero/mongrel_cluster.yml usr/share/noosfero/config/mongrel_cluster.yml -etc/noosfero/ferret_server.yml usr/share/noosfero/config/ferret_server.yml +etc/noosfero/solr.yml usr/share/noosfero/config/solr.yml etc/noosfero/plugins usr/share/noosfero/config/plugins etc/noosfero/noosfero.yml usr/share/noosfero/config/noosfero.yml etc/noosfero/local.rb usr/share/noosfero/config/local.rb diff --git a/debian/solr.yml b/debian/solr.yml new file mode 100644 index 0000000..9c2a6b2 --- /dev/null +++ b/debian/solr.yml @@ -0,0 +1,9 @@ +# Config file for the acts_as_solr plugin. +# +# If you change the host or port number here, make sure you update +# them in your Solr config file + +production: + url: http://127.0.0.1:8983/solr + jvm_options: -server -Xmx512M -Xms64M + diff --git a/etc/init.d/noosfero b/etc/init.d/noosfero index a400439..c267863 100755 --- a/etc/init.d/noosfero +++ b/etc/init.d/noosfero @@ -43,14 +43,14 @@ if [ -z "$NOOSFERO_DIR" ] || [ -z "$NOOSFERO_USER" ]; then fi ###################### -FERRET_PID_FILE=$NOOSFERO_DIR/tmp/pids/ferret.production.pid +SOLR_PID_FILE=$NOOSFERO_DIR/tmp/pids/solr.production.pid main_script() { cd $NOOSFERO_DIR if [ "$NOOSFERO_USER" != "$USER" ]; then - su $NOOSFERO_USER -l -c "./script/production $1" + su $NOOSFERO_USER -l -c "SOLR_DATA_PATH=/var/lib/noosfero-data/index ./script/production $1" else - ./script/production $1 + SOLR_DATA_PATH=/var/lib/noosfero-data/index ./script/production $1 fi } @@ -76,6 +76,13 @@ do_setup() { chmod 750 /var/tmp/noosfero fi + # Solr directory + if [ ! -d /var/tmp/noosfero/solr ]; then + mkdir -p /var/tmp/noosfero/solr + chown $NOOSFERO_USER:root /var/tmp/noosfero/solr + chmod 750 /var/tmp/noosfero/solr + fi + # symlink the directories into Noosfero directory if [ ! -e $NOOSFERO_DIR/tmp ]; then ln -s /var/tmp/noosfero $NOOSFERO_DIR/tmp @@ -90,8 +97,8 @@ do_setup() { do_start() { - # FIXME should not test for ferret only - if [ -e $FERRET_PID_FILE ]; then + # FIXME should not test for solr only + if [ -e $SOLR_PID_FILE ]; then echo 'noosfero already running, cannot start.' exit 2 fi @@ -104,8 +111,8 @@ do_start() { do_stop() { - # FIXME should not test for ferret only - if [ ! -e $FERRET_PID_FILE ]; then + # FIXME should not test for solr only + if [ ! -e $SOLR_PID_FILE ]; then echo 'noosfero not running, cannot stop' exit 2 fi diff --git a/features/browse.feature b/features/browse.feature index 2ed717f..d4ec5c4 100644 --- a/features/browse.feature +++ b/features/browse.feature @@ -4,6 +4,7 @@ Feature: browse Background: Given I am on the homepage + And the search index is empty And the following users | login | name | | joaosilva | Joao Silva | diff --git a/features/profile_search.feature b/features/profile_search.feature index 924df22..3249e00 100644 --- a/features/profile_search.feature +++ b/features/profile_search.feature @@ -4,7 +4,8 @@ Feature: search inside a profile In order to find stuff from a profile Background: - Given the following users + Given the search index is empty + And the following users | login | name | | joaosilva | Joao Silva | And the following articles diff --git a/features/search.feature b/features/search.feature index 932d843..e7aaf38 100644 --- a/features/search.feature +++ b/features/search.feature @@ -3,6 +3,9 @@ Feature: search I want to search In order to find stuff + Background: + Given the search index is empty + Scenario: simple search for person Given the following users | login | name | diff --git a/features/step_definitions/noosfero_steps.rb b/features/step_definitions/noosfero_steps.rb index 573d70b..c3e451c 100644 --- a/features/step_definitions/noosfero_steps.rb +++ b/features/step_definitions/noosfero_steps.rb @@ -488,3 +488,7 @@ Then /^"([^\"]*)" profile should not exist$/ do |profile_selector| profile.nil?.should be_true end end + +Given /^the search index is empty$/ do + ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => '*:*')) +end diff --git a/lib/acts_as_searchable.rb b/lib/acts_as_searchable.rb index 9721368..8659925 100644 --- a/lib/acts_as_searchable.rb +++ b/lib/acts_as_searchable.rb @@ -1,57 +1,67 @@ module ActsAsSearchable module ClassMethods + ACTS_AS_SEARCHABLE_ENABLED = true unless defined? ACTS_AS_SEARCHABLE_ENABLED + def acts_as_searchable(options = {}) - if Noosfero::MultiTenancy.on? and ActiveRecord::Base.postgresql? - options[:additional_fields] ||= {} - options[:additional_fields] = Hash[*options[:additional_fields].collect{ |v| [v, {}] }.flatten] if options[:additional_fields].is_a?(Array) - options[:additional_fields].merge!(:schema_name => { :index => :untokenized }) + if ACTS_AS_SEARCHABLE_ENABLED + if (!options[:fields]) + options[:additional_fields] |= [{:schema_name => :string}] + else + options[:fields] << {:schema_name => :string} + end + acts_as_solr options + extend FindByContents + send :include, InstanceMethods end - acts_as_ferret({ :remote => true }.merge(options)) - extend FindByContents - send :include, InstanceMethods end module InstanceMethods def schema_name - ActiveRecord::Base.connection.schema_search_path + (Noosfero::MultiTenancy.on? and ActiveRecord::Base.postgresql?) ? ActiveRecord::Base.connection.schema_search_path : '' end end module FindByContents def schema_name - ActiveRecord::Base.connection.schema_search_path + (Noosfero::MultiTenancy.on? and ActiveRecord::Base.postgresql?) ? ActiveRecord::Base.connection.schema_search_path : '' end - def find_by_contents(query, ferret_options = {}, db_options = {}) - pg_options = {} - if ferret_options[:page] - pg_options[:page] = ferret_options.delete(:page) - end - if ferret_options[:per_page] - pg_options[:per_page] = ferret_options.delete(:per_page) - end + def find_by_contents(query, pg_options = {}, options = {}, db_options = {}) + pg_options[:page] ||= 1 + pg_options[:per_page] ||= 20 + options[:limit] = pg_options[:per_page].to_i*pg_options[:page].to_i + options[:scores] = true; - ferret_options[:limit] = :all + query = !schema_name.empty? ? "+schema_name:\"#{schema_name}\" AND #{query}" : query + solr_result = find_by_solr(query, options) + if solr_result.nil? + results = facets = [] + else + facets = options.include?(:facets) ? solr_result.facets : [] - ferret_query = (Noosfero::MultiTenancy.on? and ActiveRecord::Base.postgresql?) ? "+schema_name:\"#{schema_name}\" AND #{query}" : query - # FIXME this is a HORRIBLE HACK - ids = find_ids_with_ferret(ferret_query, ferret_options)[1][0..8000].map{|r|r[:id].to_i} + if db_options.empty? + results = solr_result.results + else + ids = solr_result.results.map{|r|r[:id].to_i} + if ids.empty? + ids << -1 + end - if ids.empty? - ids << -1 - end + if db_options[:conditions] + db_options[:conditions] = sanitize_sql_for_conditions(db_options[:conditions]) + " and #{table_name}.id in (#{ids.join(', ')})" + else + db_options[:conditions] = "#{table_name}.id in (#{ids.join(', ')})" + end - if db_options[:conditions] - db_options[:conditions] = sanitize_sql_for_conditions(db_options[:conditions]) + " and #{table_name}.id in (#{ids.join(', ')})" - else - db_options[:conditions] = "#{table_name}.id in (#{ids.join(', ')})" + results = find(:all, db_options) + end + + results = results.paginate(pg_options.merge(:total_entries => solr_result.total)) end - pg_options[:page] ||= 1 - result = find(:all, db_options) - result.paginate(pg_options) + {:results => results, :facets => facets} end end end diff --git a/lib/create_thumbnails_job.rb b/lib/create_thumbnails_job.rb index b9dc034..a3d4e19 100644 --- a/lib/create_thumbnails_job.rb +++ b/lib/create_thumbnails_job.rb @@ -1,9 +1,7 @@ class CreateThumbnailsJob < Struct.new(:class_name, :file_id) def perform return unless class_name.constantize.exists?(file_id) - Article.disable_ferret # acts_as_ferret sucks file = class_name.constantize.find(file_id) file.create_thumbnails - Article.enable_ferret # acts_as_ferret sucks end end diff --git a/lib/tasks/cucumber.rake b/lib/tasks/cucumber.rake index d1f8faa..9b0c52e 100644 --- a/lib/tasks/cucumber.rake +++ b/lib/tasks/cucumber.rake @@ -11,6 +11,13 @@ begin vendored_cucumber_binary = Dir["#{RAILS_ROOT}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first namespace :cucumber do + task :solr_start do + ENV['RAILS_ENV'] = 'cucumber' + Rake::Task['solr:stop'].invoke + Rake::Task['solr:download'].invoke + Rake::Task['solr:start'].invoke + end + Cucumber::Rake::Task.new({:ok => 'db:test:prepare'}, 'Run features that should pass') do |t| t.binary = vendored_cucumber_binary t.fork = true # You may get faster startup if you set this to false @@ -29,11 +36,17 @@ begin t.cucumber_opts = "--color -p selenium --format #{ENV['CUCUMBER_FORMAT'] || 'pretty'}" end + task :solr_stop do + ENV['RAILS_ENV'] = 'cucumber' + Rake::Task['solr:stop'].invoke + end + desc 'Run all features' - task :all => [:ok, :wip] + task :all => [:solr_start, :ok, :wip, :solr_stop] do + end end desc 'Alias for cucumber:ok' - task :cucumber => 'cucumber:ok' + task :cucumber => ['cucumber:solr_start', 'cucumber:ok', 'cucumber:solr_stop'] task :features => :cucumber do STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***" diff --git a/lib/tasks/package.rake b/lib/tasks/package.rake index 08c2c52..c263c54 100644 --- a/lib/tasks/package.rake +++ b/lib/tasks/package.rake @@ -8,10 +8,22 @@ task :package => 'package:clobber' do puts "** The `package` task only works from within #{Noosfero::PROJECT}'s git repository." fail end + begin + sh 'test -f vendor/plugins/acts_as_solr_reloaded/solr/start.jar' + rescue + puts "** The `package` task needs Solr installed within #{Noosfero::PROJECT}. Run 'rake solr:download'." + fail + end release = "#{Noosfero::PROJECT}-#{Noosfero::VERSION}" target = "pkg/#{release}" mkdir_p target sh "git archive HEAD | (cd #{target} && tar x)" + + #solr inclusion + cp_r "vendor/plugins/acts_as_solr_reloaded/solr", "#{target}/vendor/plugins/acts_as_solr_reloaded", :verbose => true + rm_r "#{target}/vendor/plugins/acts_as_solr_reloaded/solr/work" + mkdir_p "#{target}/vendor/plugins/acts_as_solr_reloaded/solr/work" + sh "cd pkg && tar czf #{release}.tar.gz #{release}" end diff --git a/lib/tasks/test.rake b/lib/tasks/test.rake index 5149565..7dbc719 100644 --- a/lib/tasks/test.rake +++ b/lib/tasks/test.rake @@ -7,6 +7,10 @@ else end task :test do + ENV['RAILS_ENV'] = 'test' + Rake::Task['solr:stop'].invoke + Rake::Task['solr:download'].invoke + Rake::Task['solr:start'].invoke errors = %w(test:units test:functionals test:integration cucumber selenium test:noosfero_plugins).collect do |task| begin Rake::Task[task].invoke @@ -15,6 +19,7 @@ task :test do task end end.compact + Rake::Task['solr:stop'].invoke abort "Errors running #{errors.to_sentence}!" if errors.any? end diff --git a/script/development b/script/development index ce33bd9..a81c5f2 100755 --- a/script/development +++ b/script/development @@ -1,13 +1,18 @@ #!/bin/sh +export RAILS_ENV=development + stop() { ./script/delayed_job stop ./script/feed-updater stop + rake -s solr:stop } start() { ./script/feed-updater start ./script/delayed_job start + rake -s solr:download + rake -s solr:start trap stop INT TERM ./script/server $@ } diff --git a/script/ferret_server b/script/ferret_server deleted file mode 100755 index f5dbf3a..0000000 --- a/script/ferret_server +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env ruby - -begin - require File.join(File.dirname(__FILE__), '../vendor/plugins/acts_as_ferret/lib/server_manager') -rescue LoadError - # try the gem - require 'rubygems' - gem 'acts_as_ferret' - require 'server_manager' -end diff --git a/script/production b/script/production index bdf709e..3ff04b3 100755 --- a/script/production +++ b/script/production @@ -31,7 +31,7 @@ do_start() { fi clear_cache - ./script/ferret_server -e $RAILS_ENV start + rake -s solr:start environments_loop mongrel_rails cluster::start } @@ -40,7 +40,7 @@ do_stop() { mongrel_rails cluster::stop ./script/delayed_job stop ./script/feed-updater stop - ./script/ferret_server -e $RAILS_ENV stop + rake -s solr:stop } environments_loop() { diff --git a/test/factories.rb b/test/factories.rb index 0df1bf7..78bcc56 100644 --- a/test/factories.rb +++ b/test/factories.rb @@ -22,7 +22,7 @@ module Noosfero::Factory end end if options[:search] - obj.ferret_create + obj.solr_save end obj end diff --git a/test/functional/browse_controller_test.rb b/test/functional/browse_controller_test.rb index 56f11ff..1ef7dd3 100644 --- a/test/functional/browse_controller_test.rb +++ b/test/functional/browse_controller_test.rb @@ -7,6 +7,7 @@ class BrowseController; def rescue_action(e) raise e end; end class BrowseControllerTest < Test::Unit::TestCase def setup + Test::Unit::TestCase::setup @controller = BrowseController.new @request = ActionController::TestRequest.new @request.stubs(:ssl?).returns(false) diff --git a/test/functional/profile_members_controller_test.rb b/test/functional/profile_members_controller_test.rb index f9a370d..c1545f0 100644 --- a/test/functional/profile_members_controller_test.rb +++ b/test/functional/profile_members_controller_test.rb @@ -6,6 +6,7 @@ class ProfileMembersController; def rescue_action(e) raise e end; end class ProfileMembersControllerTest < Test::Unit::TestCase def setup + Test::Unit::TestCase::setup @controller = ProfileMembersController.new @request = ActionController::TestRequest.new @request.stubs(:ssl?).returns(true) diff --git a/test/functional/profile_search_controller_test.rb b/test/functional/profile_search_controller_test.rb index 0feb6f9..dd10b83 100644 --- a/test/functional/profile_search_controller_test.rb +++ b/test/functional/profile_search_controller_test.rb @@ -6,6 +6,7 @@ class ProfileSearchController; def rescue_action(e) raise e end; end class ProfileSearchControllerTest < Test::Unit::TestCase def setup + Test::Unit::TestCase::setup @controller = ProfileSearchController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new @@ -14,14 +15,6 @@ class ProfileSearchControllerTest < Test::Unit::TestCase end attr_reader :person - should 'filter stop words' do - @controller.expects(:locale).returns('en').at_least_once - get 'index', :profile => person.identifier, :q => 'an article about something' - assert_response :success - assert_template 'index' - assert_equal 'article something', assigns('filtered_query') - end - should 'espape xss attack' do @controller.expects(:profile).returns(person).at_least_once get 'index', :profile => person.identifier, :q => '' @@ -41,8 +34,8 @@ class ProfileSearchControllerTest < Test::Unit::TestCase end should 'display search results' do - article1 = fast_create(Article, :body => '

Article to test profile search

', :profile_id => person.id) - article2 = fast_create(Article, :body => '

Another article to test profile search

', :profile_id => person.id) + article1 = fast_create(Article, {:body => '

Article to test profile search

', :profile_id => person.id}, :search => true) + article2 = fast_create(Article, {:body => '

Another article to test profile search

', :profile_id => person.id}, :search => true) get 'index', :profile => person.identifier, :q => 'article' diff --git a/test/functional/search_controller_test.rb b/test/functional/search_controller_test.rb index 1f9691f..d67595b 100644 --- a/test/functional/search_controller_test.rb +++ b/test/functional/search_controller_test.rb @@ -6,6 +6,7 @@ class SearchController; def rescue_action(e) raise e end; end class SearchControllerTest < Test::Unit::TestCase def setup + Test::Unit::TestCase::setup @controller = SearchController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new @@ -35,21 +36,6 @@ class SearchControllerTest < Test::Unit::TestCase assert_valid_xhtml end - should 'filter stop words' do - @controller.expects(:locale).returns('pt_BR').at_least_once - get 'index', :query => 'a carne da vaca' - assert_response :success - assert_template 'index' - assert_equal 'carne vaca', assigns('filtered_query') - end - - should 'search with filtered query' do - @controller.expects(:locale).returns('pt_BR').at_least_once - get 'index', :query => 'a carne da vaca' - - assert_equal 'carne vaca', assigns('filtered_query') - end - should 'espape xss attack' do get 'index', :query => '' assert_no_tag :tag => 'wslite' diff --git a/test/test_helper.rb b/test/test_helper.rb index 5d953ea..f636b0b 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -47,6 +47,11 @@ class Test::Unit::TestCase include AuthenticatedTestHelper fixtures :environments, :roles + + def self.setup + # clean up index db before each test + ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => '*:*')) + end def self.all_fixtures Dir.glob(File.join(RAILS_ROOT, 'test', 'fixtures', '*.yml')).each do |item| @@ -190,7 +195,6 @@ class Test::Unit::TestCase adapter.any_instance.stubs(:adapter_name).returns('PostgreSQL') adapter.any_instance.stubs(:schema_search_path).returns(schema_name) Noosfero::MultiTenancy.stubs(:on?).returns(true) - reload_for_ferret end def uses_sqlite @@ -199,20 +203,6 @@ class Test::Unit::TestCase Noosfero::MultiTenancy.stubs(:on?).returns(false) end - def reload_for_ferret - ActsAsFerret.send(:remove_const, :DEFAULT_FIELD_OPTIONS) - load File.join(RAILS_ROOT, 'lib', 'acts_as_searchable.rb') - load File.join(RAILS_ROOT, 'vendor', 'plugins', 'acts_as_ferret', 'lib', 'acts_as_ferret.rb') - [Article, Profile, Product].each do |clazz| - inst_meth = clazz.instance_methods.reject{ |m| m =~ /_to_ferret$/ } - clazz.stubs(:instance_methods).returns(inst_meth) - end - #FIXME Is there a way to avoid this replication from model code? - Article.acts_as_searchable :additional_fields => [ :comment_data ] - Profile.acts_as_searchable :additional_fields => [ :extra_data_for_index ] - Product.acts_as_searchable :fields => [ :name, :description, :category_full_name ] - end - end module NoosferoTestHelper diff --git a/test/unit/article_test.rb b/test/unit/article_test.rb index 7ff89dd..30193bc 100644 --- a/test/unit/article_test.rb +++ b/test/unit/article_test.rb @@ -5,6 +5,7 @@ class ArticleTest < Test::Unit::TestCase fixtures :environments def setup + Test::Unit::TestCase::setup @profile = create_user('testing').person end attr_reader :profile @@ -356,7 +357,7 @@ class ArticleTest < Test::Unit::TestCase should 'reindex when comments are changed' do a = Article.new - a.expects(:ferret_update) + a.expects(:solr_save) a.comments_updated end @@ -365,7 +366,7 @@ class ArticleTest < Test::Unit::TestCase art = owner.articles.build(:name => 'ytest'); art.save! c1 = art.comments.build(:title => 'a nice comment', :body => 'anything', :author => owner); c1.save! - assert_includes Article.find_by_contents('nice'), art + assert_includes Article.find_by_contents('nice')[:results], art end should 'index comments body together with article' do @@ -373,7 +374,7 @@ class ArticleTest < Test::Unit::TestCase art = owner.articles.build(:name => 'ytest'); art.save! c1 = art.comments.build(:title => 'test comment', :body => 'anything', :author => owner); c1.save! - assert_includes Article.find_by_contents('anything'), art + assert_includes Article.find_by_contents('anything')[:results], art end should 'cache children count' do @@ -1506,24 +1507,24 @@ class ArticleTest < Test::Unit::TestCase should 'index by schema name when database is postgresql' do uses_postgresql 'schema_one' art1 = Article.create!(:name => 'some thing', :profile_id => @profile.id) - assert_equal Article.find_by_contents('thing'), [art1] + assert_equal Article.find_by_contents('thing')[:results], [art1] uses_postgresql 'schema_two' art2 = Article.create!(:name => 'another thing', :profile_id => @profile.id) - assert_not_includes Article.find_by_contents('thing'), art1 - assert_includes Article.find_by_contents('thing'), art2 + assert_not_includes Article.find_by_contents('thing')[:results], art1 + assert_includes Article.find_by_contents('thing')[:results], art2 uses_postgresql 'schema_one' - assert_includes Article.find_by_contents('thing'), art1 - assert_not_includes Article.find_by_contents('thing'), art2 + assert_includes Article.find_by_contents('thing')[:results], art1 + assert_not_includes Article.find_by_contents('thing')[:results], art2 uses_sqlite end should 'not index by schema name when database is not postgresql' do uses_sqlite art1 = Article.create!(:name => 'some thing', :profile_id => @profile.id) - assert_equal Article.find_by_contents('thing'), [art1] + assert_equal Article.find_by_contents('thing')[:results], [art1] art2 = Article.create!(:name => 'another thing', :profile_id => @profile.id) - assert_includes Article.find_by_contents('thing'), art1 - assert_includes Article.find_by_contents('thing'), art2 + assert_includes Article.find_by_contents('thing')[:results], art1 + assert_includes Article.find_by_contents('thing')[:results], art2 end should 'get images paths in article body' do diff --git a/test/unit/category_finder_test.rb b/test/unit/category_finder_test.rb index cd296f4..a397b53 100644 --- a/test/unit/category_finder_test.rb +++ b/test/unit/category_finder_test.rb @@ -3,10 +3,13 @@ require File.dirname(__FILE__) + '/../test_helper' class CategoryFinderTest < ActiveSupport::TestCase def setup + Test::Unit::TestCase::setup @category = Category.create!(:name => 'my category', :environment => Environment.default) @finder = CategoryFinder.new(@category) @product_category = fast_create(ProductCategory, :name => 'Products') + Profile.rebuild_index + Comment.skip_captcha! end should 'search for articles in a specific category' do diff --git a/test/unit/enterprise_test.rb b/test/unit/enterprise_test.rb index b454779..2cdfdf7 100644 --- a/test/unit/enterprise_test.rb +++ b/test/unit/enterprise_test.rb @@ -4,6 +4,7 @@ class EnterpriseTest < Test::Unit::TestCase fixtures :profiles, :environments, :users def setup + Test::Unit::TestCase::setup @product_category = fast_create(ProductCategory, :name => 'Products') end @@ -91,7 +92,7 @@ class EnterpriseTest < Test::Unit::TestCase ent2 = fast_create(Enterprise, :name => 'test2', :identifier => 'test2') - result = Enterprise.find_by_contents(prod_cat.name) + result = Enterprise.find_by_contents(prod_cat.name)[:results] assert_includes result, ent1 assert_not_includes result, ent2 @@ -105,7 +106,7 @@ class EnterpriseTest < Test::Unit::TestCase ent2 = fast_create(Enterprise, :name => 'test2', :identifier => 'test2') - result = Enterprise.find_by_contents(prod_cat.name) + result = Enterprise.find_by_contents(prod_cat.name)[:results] assert_includes result, ent1 assert_not_includes result, ent2 @@ -420,6 +421,12 @@ class EnterpriseTest < Test::Unit::TestCase assert_equal product.inputs, enterprise.inputs end + + should 'reindex when products are changed' do + a = Enterprise.new + a.expects(:solr_save) + a.product_updated + end should "the followed_by? be true only to members" do e = fast_create(Enterprise) diff --git a/test/unit/environment_finder_test.rb b/test/unit/environment_finder_test.rb index d30ed7e..457e58b 100644 --- a/test/unit/environment_finder_test.rb +++ b/test/unit/environment_finder_test.rb @@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/../test_helper' class EnvironmentFinderTest < ActiveSupport::TestCase def setup + Test::Unit::TestCase::setup @product_category = fast_create(ProductCategory, :name => 'Products') end @@ -77,10 +78,10 @@ class EnvironmentFinderTest < ActiveSupport::TestCase finder = EnvironmentFinder.new(Environment.default) region = fast_create(Region, :name => 'r-test', :environment_id => Environment.default.id, :lat => 45.0, :lng => 45.0) - ent1 = fast_create(Enterprise, :name => 'test 1', :identifier => 'test1', :lat => 45.0, :lng => 45.0) + ent1 = fast_create(Enterprise, {:name => 'test 1', :identifier => 'test1', :lat => 45.0, :lng => 45.0}, :search => true) p1 = create_user('test2').person p1.name = 'test 2'; p1.lat = 45.0; p1.lng = 45.0; p1.save! - ent2 = fast_create(Enterprise, :name => 'test 3', :identifier => 'test3', :lat => 30.0, :lng => 30.0) + ent2 = fast_create(Enterprise, {:name => 'test 3', :identifier => 'test3', :lat => 30.0, :lng => 30.0}, :search => true) p2 = create_user('test4').person p2.name = 'test 4'; p2.lat = 30.0; p2.lng = 30.0; p2.save! diff --git a/test/unit/environment_test.rb b/test/unit/environment_test.rb index 2437213..104425c 100644 --- a/test/unit/environment_test.rb +++ b/test/unit/environment_test.rb @@ -3,6 +3,10 @@ require File.dirname(__FILE__) + '/../test_helper' class EnvironmentTest < Test::Unit::TestCase fixtures :environments + def setup + Test::Unit::TestCase::setup + end + def test_exists_default_and_it_is_unique Environment.delete_all vc = Environment.new(:name => 'Test Community') @@ -450,7 +454,7 @@ class EnvironmentTest < Test::Unit::TestCase should 'find by contents from articles' do environment = fast_create(Environment) assert_nothing_raised do - environment.articles.find_by_contents('') + environment.articles.find_by_contents('')[:results] end end @@ -567,7 +571,7 @@ class EnvironmentTest < Test::Unit::TestCase Enterprise.create!(:name => 'test ' + n, :identifier => 'test_' + n) end - assert_equal 20, env.enterprises.find_by_contents('test').total_entries + assert_equal 20, env.enterprises.find_by_contents('test')[:results].total_entries end should 'set replace_enterprise_template_when_enable on environment' do diff --git a/test/unit/event_test.rb b/test/unit/event_test.rb index 7ff9c54..46d8d40 100644 --- a/test/unit/event_test.rb +++ b/test/unit/event_test.rb @@ -2,6 +2,10 @@ require File.dirname(__FILE__) + '/../test_helper' class EventTest < ActiveSupport::TestCase + def setup + Test::Unit::TestCase::setup + end + should 'be an article' do assert_kind_of Article, Event.new end @@ -59,13 +63,13 @@ class EventTest < ActiveSupport::TestCase should 'be indexed by title' do profile = create_user('testuser').person e = Event.create!(:name => 'my surprisingly nice event', :start_date => Date.new(2008, 06, 06), :profile => profile) - assert_includes Event.find_by_contents('surprisingly'), e + assert_includes Event.find_by_contents('surprisingly')[:results], e end should 'be indexed by body' do profile = create_user('testuser').person e = Event.create!(:name => 'bli', :start_date => Date.new(2008, 06, 06), :profile => profile, :body => 'my surprisingly long description about my freaking nice event') - assert_includes Event.find_by_contents('surprisingly'), e + assert_includes Event.find_by_contents('surprisingly')[:results], e end should 'use its own icon' do diff --git a/test/unit/forum_helper_test.rb b/test/unit/forum_helper_test.rb index a0f0c84..cbeccbf 100644 --- a/test/unit/forum_helper_test.rb +++ b/test/unit/forum_helper_test.rb @@ -50,14 +50,14 @@ class ForumHelperTest < Test::Unit::TestCase some_post.comments << Comment.new(:title => 'test', :body => 'test', :author => a2) c = Comment.last assert_equal 2, some_post.comments.count - assert_match /#{c.created_at.to_s} ago by a2<\/a>/, last_topic_update(some_post) + assert_match(/#{Regexp.escape(c.created_at.to_s)} ago by a2<\/a>/, last_topic_update(some_post)) end should "return last comment author's name from unauthenticated user" do some_post = TextileArticle.create!(:name => 'First post', :profile => profile, :parent => forum, :published => true) some_post.comments << Comment.new(:name => 'John', :email => 'lenon@example.com', :title => 'test', :body => 'test') c = Comment.last - assert_match /#{c.created_at.to_s} ago by John/m, last_topic_update(some_post) + assert_match(/#{Regexp.escape(c.created_at.to_s)} ago by John/m, last_topic_update(some_post)) end protected diff --git a/test/unit/product_test.rb b/test/unit/product_test.rb index 3e643c0..66f325e 100644 --- a/test/unit/product_test.rb +++ b/test/unit/product_test.rb @@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/../test_helper' class ProductTest < Test::Unit::TestCase def setup + Test::Unit::TestCase::setup @product_category = fast_create(ProductCategory, :name => 'Products') end @@ -92,7 +93,7 @@ class ProductTest < Test::Unit::TestCase p.stubs(:category_full_name).returns('interesting category') p.save! - assert_includes Product.find_by_contents('interesting'), p + assert_includes Product.find_by_contents('interesting')[:results], p end should 'have same lat and lng of its enterprise' do @@ -362,24 +363,24 @@ class ProductTest < Test::Unit::TestCase should 'index by schema name when database is postgresql' do uses_postgresql 'schema_one' p1 = Product.create!(:name => 'some thing', :product_category => @product_category) - assert_equal Product.find_by_contents('thing'), [p1] + assert_equal Product.find_by_contents('thing')[:results], [p1] uses_postgresql 'schema_two' p2 = Product.create!(:name => 'another thing', :product_category => @product_category) - assert_not_includes Product.find_by_contents('thing'), p1 - assert_includes Product.find_by_contents('thing'), p2 + assert_not_includes Product.find_by_contents('thing')[:results], p1 + assert_includes Product.find_by_contents('thing')[:results], p2 uses_postgresql 'schema_one' - assert_includes Product.find_by_contents('thing'), p1 - assert_not_includes Product.find_by_contents('thing'), p2 + assert_includes Product.find_by_contents('thing')[:results], p1 + assert_not_includes Product.find_by_contents('thing')[:results], p2 uses_sqlite end should 'not index by schema name when database is not postgresql' do uses_sqlite p1 = Product.create!(:name => 'some thing', :product_category => @product_category) - assert_equal Product.find_by_contents('thing'), [p1] + assert_equal Product.find_by_contents('thing')[:results], [p1] p2 = Product.create!(:name => 'another thing', :product_category => @product_category) - assert_includes Product.find_by_contents('thing'), p1 - assert_includes Product.find_by_contents('thing'), p2 + assert_includes Product.find_by_contents('thing')[:results], p1 + assert_includes Product.find_by_contents('thing')[:results], p2 end end diff --git a/test/unit/profile_test.rb b/test/unit/profile_test.rb index 9385379..4c8a445 100644 --- a/test/unit/profile_test.rb +++ b/test/unit/profile_test.rb @@ -3,6 +3,10 @@ require File.dirname(__FILE__) + '/../test_helper' class ProfileTest < Test::Unit::TestCase fixtures :profiles, :environments, :users, :roles, :domains + def setup + Test::Unit::TestCase::setup + end + def test_identifier_validation p = Profile.new p.valid? @@ -100,8 +104,8 @@ class ProfileTest < Test::Unit::TestCase def test_find_by_contents p = create(Profile, :name => 'wanted') - assert Profile.find_by_contents('wanted').include?(p) - assert ! Profile.find_by_contents('not_wanted').include?(p) + assert Profile.find_by_contents('wanted')[:results].include?(p) + assert ! Profile.find_by_contents('not_wanted')[:results].include?(p) end should 'remove pages when removing profile' do @@ -192,10 +196,10 @@ class ProfileTest < Test::Unit::TestCase small = create(Profile, :name => 'A small profile for testing') big = create(Profile, :name => 'A big profile for testing') - assert Profile.find_by_contents('small').include?(small) - assert Profile.find_by_contents('big').include?(big) + assert Profile.find_by_contents('small')[:results].include?(small) + assert Profile.find_by_contents('big')[:results].include?(big) - both = Profile.find_by_contents('profile testing') + both = Profile.find_by_contents('profile testing')[:results] assert both.include?(small) assert both.include?(big) end @@ -517,18 +521,18 @@ class ProfileTest < Test::Unit::TestCase should 'actually index by results of extra_data_for_index' do profile = TestingExtraDataForIndex.create!(:name => 'testprofile', :identifier => 'testprofile') - assert_includes TestingExtraDataForIndex.find_by_contents('sample'), profile + assert_includes TestingExtraDataForIndex.find_by_contents('sample')[:results], profile end should 'index profile identifier for searching' do Profile.destroy_all p = create(Profile, :identifier => 'lalala') - assert_includes Profile.find_by_contents('lalala'), p + assert_includes Profile.find_by_contents('lalala')[:results], p end should 'index profile name for searching' do p = create(Profile, :name => 'Interesting Profile') - assert_includes Profile.find_by_contents('interesting'), p + assert_includes Profile.find_by_contents('interesting')[:results], p end should 'enabled by default on creation' do @@ -1665,24 +1669,24 @@ class ProfileTest < Test::Unit::TestCase should 'index by schema name when database is postgresql' do uses_postgresql 'schema_one' p1 = Profile.create!(:name => 'some thing', :identifier => 'some-thing') - assert_equal Profile.find_by_contents('thing'), [p1] + assert_equal Profile.find_by_contents('thing')[:results], [p1] uses_postgresql 'schema_two' p2 = Profile.create!(:name => 'another thing', :identifier => 'another-thing') - assert_not_includes Profile.find_by_contents('thing'), p1 - assert_includes Profile.find_by_contents('thing'), p2 + assert_not_includes Profile.find_by_contents('thing')[:results], p1 + assert_includes Profile.find_by_contents('thing')[:results], p2 uses_postgresql 'schema_one' - assert_includes Profile.find_by_contents('thing'), p1 - assert_not_includes Profile.find_by_contents('thing'), p2 + assert_includes Profile.find_by_contents('thing')[:results], p1 + assert_not_includes Profile.find_by_contents('thing')[:results], p2 uses_sqlite end should 'not index by schema name when database is not postgresql' do uses_sqlite p1 = Profile.create!(:name => 'some thing', :identifier => 'some-thing') - assert_equal Profile.find_by_contents('thing'), [p1] + assert_equal Profile.find_by_contents('thing')[:results], [p1] p2 = Profile.create!(:name => 'another thing', :identifier => 'another-thing') - assert_includes Profile.find_by_contents('thing'), p1 - assert_includes Profile.find_by_contents('thing'), p2 + assert_includes Profile.find_by_contents('thing')[:results], p1 + assert_includes Profile.find_by_contents('thing')[:results], p2 end should 'know if url is the profile homepage' do diff --git a/test/unit/tiny_mce_article_test.rb b/test/unit/tiny_mce_article_test.rb index 0b066fa..9662764 100644 --- a/test/unit/tiny_mce_article_test.rb +++ b/test/unit/tiny_mce_article_test.rb @@ -3,7 +3,8 @@ require File.dirname(__FILE__) + '/../test_helper' class TinyMceArticleTest < Test::Unit::TestCase def setup - Article.rebuild_index + Test::Unit::TestCase::setup + Article.rebuild_solr_index @profile = create_user('zezinho').person end attr_reader :profile @@ -23,8 +24,8 @@ class TinyMceArticleTest < Test::Unit::TestCase should 'be found when searching for articles by query' do tma = TinyMceArticle.create!(:name => 'test tinymce article', :body => '---', :profile => profile) - assert_includes TinyMceArticle.find_by_contents('article'), tma - assert_includes Article.find_by_contents('article'), tma + assert_includes TinyMceArticle.find_by_contents('article')[:results], tma + assert_includes Article.find_by_contents('article')[:results], tma end should 'not sanitize target attribute' do diff --git a/vendor/plugins/access_control/init.rb b/vendor/plugins/access_control/init.rb index d3e6ddc..3ce5421 100644 --- a/vendor/plugins/access_control/init.rb +++ b/vendor/plugins/access_control/init.rb @@ -2,5 +2,5 @@ require 'acts_as_accessor' require 'acts_as_accessible' require 'permission_name_helper' module ApplicationHelper - include PermissionName + include PermissionNameHelper end diff --git a/vendor/plugins/access_control/lib/permission_name_helper.rb b/vendor/plugins/access_control/lib/permission_name_helper.rb index b67f02e..1e9a52d 100644 --- a/vendor/plugins/access_control/lib/permission_name_helper.rb +++ b/vendor/plugins/access_control/lib/permission_name_helper.rb @@ -1,4 +1,4 @@ -module PermissionName +module PermissionNameHelper def permission_name(p) msgid = ActiveRecord::Base::PERMISSIONS.values.inject({}){|s,v| s.merge(v)}[p] gettext(msgid) diff --git a/vendor/plugins/acts_as_ferret/LICENSE b/vendor/plugins/acts_as_ferret/LICENSE deleted file mode 100644 index b07e5a5..0000000 --- a/vendor/plugins/acts_as_ferret/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2006 Kasper Weibel, Jens Kraemer - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/plugins/acts_as_ferret/README b/vendor/plugins/acts_as_ferret/README deleted file mode 100644 index dae041c..0000000 --- a/vendor/plugins/acts_as_ferret/README +++ /dev/null @@ -1,53 +0,0 @@ -= acts_as_ferret - -This ActiveRecord mixin adds full text search capabilities to any Rails model. - -It is heavily based on the original acts_as_ferret plugin done by -Kasper Weibel and a modified version done by Thomas Lockney, which -both can be found on http://ferret.davebalmain.com/trac/wiki/FerretOnRails - -== Installation - -=== Installation inside your Rails project via script/plugin - -script/plugin install svn://projects.jkraemer.net/acts_as_ferret/trunk/plugin/acts_as_ferret - -Aaf is is also available via git from Rubyforge: -git clone git://rubyforge.org/actsasferret.git - -=== System-wide installation with Rubygems - -sudo gem install acts_as_ferret - -To use acts_as_ferret in your project, add the following line to your -project's config/environment.rb: - -require 'acts_as_ferret' - -Call the aaf_install script inside your project directory to install the sample -config file and the drb server start/stop script. - - -== Usage - -include the following in your model class (specifiying the fields you want to get indexed): - -acts_as_ferret :fields => [ :title, :description ] - -now you can use ModelClass.find_by_contents(query) to find instances of your model -whose indexed fields match a given query. All query terms are required by default, -but explicit OR queries are possible. This differs from the ferret default, but -imho is the more often needed/expected behaviour (more query terms result in -less results). - -Please see ActsAsFerret::ActMethods#acts_as_ferret for more information. - -== License - -Released under the MIT license. - -== Authors - -* Kasper Weibel Nielsen-Refs (original author) -* Jens Kraemer (current maintainer) - diff --git a/vendor/plugins/acts_as_ferret/bin/aaf_install b/vendor/plugins/acts_as_ferret/bin/aaf_install deleted file mode 100644 index 31ed6bb..0000000 --- a/vendor/plugins/acts_as_ferret/bin/aaf_install +++ /dev/null @@ -1,23 +0,0 @@ -# acts_as_ferret gem install script -# Use inside the root of your Rails project -require 'fileutils' - -@basedir = File.join(File.dirname(__FILE__), '..') - -def install(dir, file, executable=false) - puts "Installing: #{file}" - target = File.join('.', dir, file) - if File.exists?(target) - puts "#{target} already exists, skipping" - else - FileUtils.cp File.join(@basedir, dir, file), target - FileUtils.chmod 0755, target if executable - end -end - - -install 'script', 'ferret_server', true -install 'config', 'ferret_server.yml' - -puts IO.read(File.join(@basedir, 'README')) - diff --git a/vendor/plugins/acts_as_ferret/config/ferret_server.yml b/vendor/plugins/acts_as_ferret/config/ferret_server.yml deleted file mode 100644 index 402e54e..0000000 --- a/vendor/plugins/acts_as_ferret/config/ferret_server.yml +++ /dev/null @@ -1,24 +0,0 @@ -# configuration for the acts_as_ferret DRb server -# host: where to reach the DRb server (used by application processes to contact the server) -# port: which port the server should listen on -# socket: where the DRb server should create the socket (absolute path), this setting overrides host:port configuration -# pid_file: location of the server's pid file (relative to RAILS_ROOT) -# log_file: log file (default: RAILS_ROOT/log/ferret_server.log -# log_level: log level for the server's logger -production: - host: localhost - port: 9010 - pid_file: log/ferret.pid - log_file: log/ferret_server.log - log_level: warn - -# aaf won't try to use the DRb server in environments that are not -# configured here. -#development: -# host: localhost -# port: 9010 -# pid_file: log/ferret.pid -#test: -# host: localhost -# port: 9009 -# pid_file: log/ferret.pid diff --git a/vendor/plugins/acts_as_ferret/doc/README.win32 b/vendor/plugins/acts_as_ferret/doc/README.win32 deleted file mode 100644 index 97bb465..0000000 --- a/vendor/plugins/acts_as_ferret/doc/README.win32 +++ /dev/null @@ -1,23 +0,0 @@ -Credits -======= - -The Win32 service support scripts have been written by -Herryanto Siatono . - -See his accompanying blog posting at -http://www.pluitsolutions.com/2007/07/30/acts-as-ferret-drbserver-win32-service/ - - -Usage -===== - -There are two scripts: - -script/ferret_service is used to install/remove/start/stop the win32 service. - -script/ferret_daemon is to be called by Win32 service to start/stop the -DRbServer. - -Run 'ruby script/ferret_service -h' for more info. - - diff --git a/vendor/plugins/acts_as_ferret/doc/monit-example b/vendor/plugins/acts_as_ferret/doc/monit-example deleted file mode 100644 index a37c5eb..0000000 --- a/vendor/plugins/acts_as_ferret/doc/monit-example +++ /dev/null @@ -1,22 +0,0 @@ -# monit configuration snippet to watch the Ferret DRb server shipped with -# acts_as_ferret -check process ferret with pidfile /path/to/ferret.pid - - # username is the user the drb server should be running as (It's good practice - # to run such services as a non-privileged user) - start program = "/bin/su -c 'cd /path/to/your/app/current/ && script/ferret_server -e production start' username" - stop program = "/bin/su -c 'cd /path/to/your/app/current/ && script/ferret_server -e production stop' username" - - # cpu usage boundaries - if cpu > 60% for 2 cycles then alert - if cpu > 90% for 5 cycles then restart - - # memory usage varies with index size and usage scenarios, so check how - # much memory your DRb server uses up usually and add some spare to that - # before enabling this rule: - # if totalmem > 50.0 MB for 5 cycles then restart - - # adjust port numbers according to your setup: - if failed port 9010 then alert - if failed port 9010 for 2 cycles then restart - group ferret diff --git a/vendor/plugins/acts_as_ferret/init.rb b/vendor/plugins/acts_as_ferret/init.rb deleted file mode 100644 index a15a3cd..0000000 --- a/vendor/plugins/acts_as_ferret/init.rb +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2006 Kasper Weibel Nielsen-Refs, Thomas Lockney, Jens Krämer -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -require 'acts_as_ferret' - -config.after_initialize { ActsAsFerret::load_config } -config.to_prepare { ActsAsFerret::load_config } diff --git a/vendor/plugins/acts_as_ferret/install.rb b/vendor/plugins/acts_as_ferret/install.rb deleted file mode 100644 index 2a28aa6..0000000 --- a/vendor/plugins/acts_as_ferret/install.rb +++ /dev/null @@ -1,18 +0,0 @@ -# acts_as_ferret install script -require 'fileutils' - -def install(file) - puts "Installing: #{file}" - target = File.join(File.dirname(__FILE__), '..', '..', '..', file) - if File.exists?(target) - puts "target #{target} already exists, skipping" - else - FileUtils.cp File.join(File.dirname(__FILE__), file), target - end -end - -install File.join( 'script', 'ferret_server' ) -install File.join( 'config', 'ferret_server.yml' ) - -puts IO.read(File.join(File.dirname(__FILE__), 'README')) - diff --git a/vendor/plugins/acts_as_ferret/lib/act_methods.rb b/vendor/plugins/acts_as_ferret/lib/act_methods.rb deleted file mode 100644 index 9785819..0000000 --- a/vendor/plugins/acts_as_ferret/lib/act_methods.rb +++ /dev/null @@ -1,155 +0,0 @@ -module ActsAsFerret #:nodoc: - - # This module defines the acts_as_ferret method and is included into - # ActiveRecord::Base - module ActMethods - - - def reloadable?; false end - - # declares a class as ferret-searchable. - # - # ====options: - # fields:: names all fields to include in the index. If not given, - # all attributes of the class will be indexed. You may also give - # symbols pointing to instance methods of your model here, i.e. - # to retrieve and index data from a related model. - # - # additional_fields:: names fields to include in the index, in addition - # to those derived from the db scheme. use if you want - # to add custom fields derived from methods to the db - # fields (which will be picked by aaf). This option will - # be ignored when the fields option is given, in that - # case additional fields get specified there. - # - # if:: Can be set to a block that will be called with the record in question - # to determine if it should be indexed or not. - # - # index_dir:: declares the directory where to put the index for this class. - # The default is RAILS_ROOT/index/RAILS_ENV/CLASSNAME. - # The index directory will be created if it doesn't exist. - # - # reindex_batch_size:: reindexing is done in batches of this size, default is 1000 - # mysql_fast_batches:: set this to false to disable the faster mysql batching - # algorithm if this model uses a non-integer primary key named - # 'id' on MySQL. - # - # ferret:: Hash of Options that directly influence the way the Ferret engine works. You - # can use most of the options the Ferret::I class accepts here, too. Among the - # more useful are: - # - # or_default:: whether query terms are required by - # default (the default, false), or not (true) - # - # analyzer:: the analyzer to use for query parsing (default: nil, - # which means the ferret StandardAnalyzer gets used) - # - # default_field:: use to set one or more fields that are searched for query terms - # that don't have an explicit field list. This list should *not* - # contain any untokenized fields. If it does, you're asking - # for trouble (i.e. not getting results for queries having - # stop words in them). Aaf by default initializes the default field - # list to contain all tokenized fields. If you use :single_index => true, - # you really should set this option specifying your default field - # list (which should be equal in all your classes sharing the index). - # Otherwise you might get incorrect search results and you won't get - # any lazy loading of stored field data. - # - # For downwards compatibility reasons you can also specify the Ferret options in the - # last Hash argument. - def acts_as_ferret(options={}) - - extend ClassMethods - - include InstanceMethods - include MoreLikeThis::InstanceMethods - - if options[:rdig] - cattr_accessor :rdig_configuration - self.rdig_configuration = options[:rdig] - require 'rdig_adapter' - include ActsAsFerret::RdigAdapter - end - - unless included_modules.include?(ActsAsFerret::WithoutAR) - # set up AR hooks - after_create :ferret_create - after_update :ferret_update - after_destroy :ferret_destroy - end - - cattr_accessor :aaf_configuration - - # apply default config for rdig based models - if options[:rdig] - options[:fields] ||= { :title => { :boost => 3, :store => :yes }, - :content => { :store => :yes } } - end - - # name of this index - index_name = options.delete(:index) || self.name.underscore - - index = ActsAsFerret::register_class_with_index(self, index_name, options) - self.aaf_configuration = index.index_definition.dup - logger.debug "configured index for class #{self.name}:\n#{aaf_configuration.inspect}" - - # update our copy of the global index config with options local to this class - aaf_configuration[:class_name] ||= self.name - aaf_configuration[:if] ||= options[:if] - - # add methods for retrieving field values - add_fields options[:fields] - add_fields options[:additional_fields] - add_fields aaf_configuration[:fields] - add_fields aaf_configuration[:additional_fields] - - # not good at class level, index might get initialized too early - #if options[:remote] - # aaf_index.ensure_index_exists - #end - end - - - protected - - - # helper to defines a method which adds the given field to a ferret - # document instance - def define_to_field_method(field, options = {}) - method_name = "#{field}_to_ferret" - return if instance_methods.include?(method_name) # already defined - aaf_configuration[:defined_fields] ||= {} - aaf_configuration[:defined_fields][field] = options - dynamic_boost = options[:boost] if options[:boost].is_a?(Symbol) - via = options[:via] || field - define_method(method_name.to_sym) do - val = begin - content_for_field_name(field, via, dynamic_boost) - rescue - logger.warn("Error retrieving value for field #{field}: #{$!}") - '' - end - logger.debug("Adding field #{field} with value '#{val}' to index") - val - end - end - - def add_fields(field_config) - # TODO - #field_config.each do |*args| - # define_to_field_method *args - #end - if field_config.is_a? Hash - field_config.each_pair do |field, options| - define_to_field_method field, options - end - elsif field_config.respond_to?(:each) - field_config.each do |field| - define_to_field_method field - end - end - end - - end - -end diff --git a/vendor/plugins/acts_as_ferret/lib/acts_as_ferret.rb b/vendor/plugins/acts_as_ferret/lib/acts_as_ferret.rb deleted file mode 100644 index b2b48ac..0000000 --- a/vendor/plugins/acts_as_ferret/lib/acts_as_ferret.rb +++ /dev/null @@ -1,567 +0,0 @@ -# Copyright (c) 2006 Kasper Weibel Nielsen-Refs, Thomas Lockney, Jens Krämer -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -require 'active_support' -require 'active_record' -require 'set' -require 'enumerator' -require 'ferret' - -require 'ferret_find_methods' -require 'remote_functions' -require 'blank_slate' -require 'bulk_indexer' -require 'ferret_extensions' -require 'act_methods' -require 'search_results' -require 'class_methods' -require 'ferret_result' -require 'instance_methods' -require 'without_ar' - -require 'multi_index' -require 'remote_multi_index' -require 'more_like_this' - -require 'index' -require 'local_index' -require 'remote_index' - -require 'ferret_server' - -require 'rdig_adapter' - -# The Rails ActiveRecord Ferret Mixin. -# -# This mixin adds full text search capabilities to any Rails model. -# -# The current version emerged from on the original acts_as_ferret plugin done by -# Kasper Weibel and a modified version done by Thomas Lockney, which both can be -# found on the Ferret Wiki: http://ferret.davebalmain.com/trac/wiki/FerretOnRails. -# -# basic usage: -# include the following in your model class (specifiying the fields you want to get indexed): -# acts_as_ferret :fields => [ :title, :description ] -# -# now you can use ModelClass.find_by_contents(query) to find instances of your model -# whose indexed fields match a given query. All query terms are required by default, but -# explicit OR queries are possible. This differs from the ferret default, but imho is the more -# often needed/expected behaviour (more query terms result in less results). -# -# Released under the MIT license. -# -# Authors: -# Kasper Weibel Nielsen-Refs (original author) -# Jens Kraemer (active maintainer since 2006) -# -# -# == Global properties -# -# raise_drb_errors:: Set this to true if you want aaf to raise Exceptions -# in case the DRb server cannot be reached (in other word - behave like -# versions up to 0.4.3). Defaults to false so DRb exceptions -# are logged but not raised. Be sure to set up some -# monitoring so you still detect when your DRb server died for -# whatever reason. -# -# remote:: Set this to false to force acts_as_ferret into local (non-DRb) mode even if -# config/ferret_server.yml contains a section for the current RAILS_ENV -# Usually you won't need to touch this option - just configure DRb for -# production mode in ferret_server.yml. -# -module ActsAsFerret - - class ActsAsFerretError < StandardError; end - class IndexNotDefined < ActsAsFerretError; end - class IndexAlreadyDefined < ActsAsFerretError; end - - # global Hash containing all multi indexes created by all classes using the plugin - # key is the concatenation of alphabetically sorted names of the classes the - # searcher searches. - @@multi_indexes = Hash.new - def self.multi_indexes; @@multi_indexes end - - # global Hash containing the ferret indexes of all classes using the plugin - # key is the index name. - @@ferret_indexes = Hash.new - def self.ferret_indexes; @@ferret_indexes end - - # mapping from class name to index name - @@index_using_classes = {} - - @@logger = Logger.new "#{RAILS_ROOT}/log/acts_as_ferret.log" - @@logger.level = ActiveRecord::Base.logger.level rescue Logger::DEBUG - mattr_accessor :logger - - - # Default ferret configuration for index fields - DEFAULT_FIELD_OPTIONS = { - :store => :no, - :highlight => :yes, - :index => :yes, - :term_vector => :with_positions_offsets, - :boost => 1.0 - } - - @@raise_drb_errors = false - mattr_writer :raise_drb_errors - def self.raise_drb_errors?; @@raise_drb_errors end - - @@remote = nil - mattr_accessor :remote - def self.remote? - if @@remote.nil? - if ENV["FERRET_USE_LOCAL_INDEX"] || ActsAsFerret::Remote::Server.running - @@remote = false - else - @@remote = ActsAsFerret::Remote::Config.new.uri rescue false - end - if @@remote - logger.info "Will use remote index server which should be available at #{@@remote}" - else - logger.info "Will use local index." - end - end - @@remote - end - remote? - - - # Globally declares an index. - # - # This method is also used to implicitly declare an index when you use the - # acts_as_ferret call in your class. Returns the created index instance. - # - # === Options are: - # - # +models+:: Hash of model classes and their per-class option hashes which should - # use this index. Any models mentioned here will automatically use - # the index, there is no need to explicitly call +acts_as_ferret+ in the - # model class definition. - def self.define_index(name, options = {}) - name = name.to_sym - pending_classes = nil - if ferret_indexes.has_key?(name) - # seems models have been already loaded. remove that index for now, - # re-register any already loaded classes later on. - idx = get_index(name) - pending_classes = idx.index_definition[:registered_models] - pending_classes_configs = idx.registered_models_config - idx.close - ferret_indexes.delete(name) - end - - index_definition = { - :index_dir => "#{ActsAsFerret::index_dir}/#{name}", - :name => name, - :single_index => false, - :reindex_batch_size => 1000, - :ferret => {}, - :ferret_fields => {}, # list of indexed fields that will be filled later - :enabled => true, # used for class-wide disabling of Ferret - :mysql_fast_batches => true, # turn off to disable the faster, id based batching mechanism for MySQL - :raise_drb_errors => false # handle DRb connection errors by default - }.update( options ) - - index_definition[:registered_models] = [] - - # build ferret configuration - index_definition[:ferret] = { - :or_default => false, - :handle_parse_errors => true, - :default_field => nil, # will be set later on - #:max_clauses => 512, - #:analyzer => Ferret::Analysis::StandardAnalyzer.new, - # :wild_card_downcase => true - }.update( options[:ferret] || {} ) - - index_definition[:user_default_field] = index_definition[:ferret][:default_field] - - unless remote? - ActsAsFerret::ensure_directory index_definition[:index_dir] - index_definition[:index_base_dir] = index_definition[:index_dir] - index_definition[:index_dir] = find_last_index_version(index_definition[:index_dir]) - logger.debug "using index in #{index_definition[:index_dir]}" - end - - # these properties are somewhat vital to the plugin and shouldn't - # be overwritten by the user: - index_definition[:ferret].update( - :key => ((Noosfero::MultiTenancy.on? and ActiveRecord::Base.postgresql?) ? [:id, :class_name, :schema_name] : [:id, :class_name]), - :path => index_definition[:index_dir], - :auto_flush => true, # slower but more secure in terms of locking problems TODO disable when running in drb mode? - :create_if_missing => true - ) - - # field config - index_definition[:ferret_fields] = build_field_config( options[:fields] ) - index_definition[:ferret_fields].update build_field_config( options[:additional_fields] ) - - idx = ferret_indexes[name] = create_index_instance( index_definition ) - - # re-register early loaded classes - if pending_classes - pending_classes.each { |clazz| idx.register_class clazz, { :force_re_registration => true }.merge(pending_classes_configs[clazz]) } - end - - if models = options[:models] - models.each do |clazz, config| - clazz.send :include, ActsAsFerret::WithoutAR unless clazz.respond_to?(:acts_as_ferret) - clazz.acts_as_ferret config.merge(:index => name) - end - end - - return idx - end - - # called internally by the acts_as_ferret method - # - # returns the index - def self.register_class_with_index(clazz, index_name, options = {}) - index_name = index_name.to_sym - @@index_using_classes[clazz.name] = index_name - unless index = ferret_indexes[index_name] - # index definition on the fly - # default to all attributes of this class - options[:fields] ||= clazz.new.attributes.keys.map { |k| k.to_sym } - index = define_index index_name, options - end - index.register_class(clazz, options) - return index - end - - def self.load_config - # using require_dependency to make the reloading in dev mode work. - require_dependency "#{RAILS_ROOT}/config/aaf.rb" - ActsAsFerret::logger.info "loaded configuration file aaf.rb" - rescue LoadError - ensure - @aaf_config_loaded = true - end - - # returns the index with the given name. - def self.get_index(name) - name = name.to_sym rescue nil - unless ferret_indexes.has_key?(name) - if @aaf_config_loaded - raise IndexNotDefined.new(name.to_s) - else - load_config and return get_index name - end - end - ferret_indexes[name] - end - - # count hits for a query with multiple models - def self.total_hits(query, models, options = {}) - find_index(models).total_hits query, options.merge( :models => models ) - end - - # find ids of records with multiple models - # TODO pagination logic? - def self.find_ids(query, models, options = {}, &block) - find_index(models).find_ids query, options.merge( :models => models ), &block - end - - def self.find_index(models_or_index_name) - case models_or_index_name - when Symbol - get_index models_or_index_name - when String - get_index models_or_index_name.to_sym - #when Array - # get_index_for models_or_index_name - else - get_index_for models_or_index_name - end - end - - def self.find(query, models_or_index_name, options = {}, ar_options = {}) - # TODO generalize local/remote index so we can remove the workaround below - # (replace logic in class_methods#find_with_ferret) - # maybe put pagination stuff in a module to be included by all index - # implementations - models = [ models_or_index_name ] if Class === models_or_index_name - if models && models.size == 1 - return models.shift.find_with_ferret query, options, ar_options - end - index = find_index(models_or_index_name) - multi = (MultiIndex === index or index.shared?) - if options[:per_page] - options[:page] = options[:page] ? options[:page].to_i : 1 - limit = options[:per_page] - offset = (options[:page] - 1) * limit - if ar_options[:conditions] && !multi - ar_options[:limit] = limit - ar_options[:offset] = offset - options[:limit] = :all - options.delete :offset - else - # do pagination with ferret (or after everything is done in the case - # of multi_search) - options[:limit] = limit - options[:offset] = offset - end - elsif ar_options[:conditions] - if multi - # multisearch ignores find_options limit and offset - options[:limit] ||= ar_options.delete(:limit) - options[:offset] ||= ar_options.delete(:offset) - else - # let the db do the limiting and offsetting for single-table searches - unless options[:limit] == :all - ar_options[:limit] ||= options.delete(:limit) - end - ar_options[:offset] ||= options.delete(:offset) - options[:limit] = :all - end - end - - total_hits, result = index.find_records query, options.merge(:models => models), ar_options - logger.debug "Query: #{query}\ntotal hits: #{total_hits}, results delivered: #{result.size}" - SearchResults.new(result, total_hits, options[:page], options[:per_page]) - end - - # returns the index used by the given class. - # - # If multiple classes are given, either the single index shared by these - # classes, or a multi index (to be used for search only) across the indexes - # of all models, is returned. - def self.get_index_for(*classes) - classes.flatten! - raise ArgumentError.new("no class specified") unless classes.any? - classes.map!(&:constantize) unless Class === classes.first - logger.debug "index_for #{classes.inspect}" - index = if classes.size > 1 - indexes = classes.map { |c| get_index_for c }.uniq - indexes.size > 1 ? multi_index(indexes) : indexes.first - else - clazz = classes.first - clazz = clazz.superclass while clazz && !@@index_using_classes.has_key?(clazz.name) - get_index @@index_using_classes[clazz.name] - end - raise IndexNotDefined.new("no index found for class: #{classes.map(&:name).join(',')}") if index.nil? - return index - end - - - # creates a new Index instance. - def self.create_index_instance(definition) - (remote? ? RemoteIndex : LocalIndex).new(definition) - end - - def self.rebuild_index(name) - get_index(name).rebuild_index - end - - def self.change_index_dir(name, new_dir) - get_index(name).change_index_dir new_dir - end - - # find the most recent version of an index - def self.find_last_index_version(basedir) - # check for versioned index - versions = Dir.entries(basedir).select do |f| - dir = File.join(basedir, f) - File.directory?(dir) && File.file?(File.join(dir, 'segments')) && f =~ /^\d+(_\d+)?$/ - end - if versions.any? - # select latest version - versions.sort! - File.join basedir, versions.last - else - basedir - end - end - - # returns a MultiIndex instance operating on a MultiReader - def self.multi_index(indexes) - index_names = indexes.dup - index_names = index_names.map(&:to_s) if Symbol === index_names.first - if String === index_names.first - indexes = index_names.map{ |name| get_index name } - else - index_names = index_names.map{ |i| i.index_name.to_s } - end - key = index_names.sort.join(",") - ActsAsFerret::multi_indexes[key] ||= (remote? ? ActsAsFerret::RemoteMultiIndex : ActsAsFerret::MultiIndex).new(indexes) - end - - # check for per-model conditions and return these if provided - def self.conditions_for_model(model, conditions = {}) - if Hash === conditions - key = model.name.underscore.to_sym - conditions = conditions[key] - end - return conditions - end - - # retrieves search result records from a data structure like this: - # { 'Model1' => { '1' => [ rank, score ], '2' => [ rank, score ] } - # - # TODO: in case of STI AR will filter out hits from other - # classes for us, but this - # will lead to less results retrieved --> scoping of ferret query - # to self.class is still needed. - # from the ferret ML (thanks Curtis Hatter) - # > I created a method in my base STI class so I can scope my query. For scoping - # > I used something like the following line: - # > - # > query << " role:#{self.class.eql?(Contents) '*' : self.class}" - # > - # > Though you could make it more generic by simply asking - # > "self.descends_from_active_record?" which is how rails decides if it should - # > scope your "find" query for STI models. You can check out "base.rb" in - # > activerecord to see that. - # but maybe better do the scoping in find_ids_with_ferret... - def self.retrieve_records(id_arrays, find_options = {}) - result = [] - # get objects for each model - id_arrays.each do |model, id_array| - next if id_array.empty? - model_class = model.constantize - - # merge conditions - conditions = conditions_for_model model_class, find_options[:conditions] - conditions = combine_conditions([ "#{model_class.table_name}.#{model_class.primary_key} in (?)", - id_array.keys ], - conditions) - - # check for include association that might only exist on some models in case of multi_search - filtered_include_options = [] - if include_options = find_options[:include] - include_options = [ include_options ] unless include_options.respond_to?(:each) - include_options.each do |include_option| - filtered_include_options << include_option if model_class.reflections.has_key?(include_option.is_a?(Hash) ? include_option.keys[0].to_sym : include_option.to_sym) - end - end - filtered_include_options = nil if filtered_include_options.empty? - - # fetch - tmp_result = model_class.find(:all, find_options.merge(:conditions => conditions, - :include => filtered_include_options)) - - # set scores and rank - tmp_result.each do |record| - record.ferret_rank, record.ferret_score = id_array[record.id.to_s] - end - # merge with result array - result += tmp_result - end - - # order results as they were found by ferret, unless an AR :order - # option was given - result.sort! { |a, b| a.ferret_rank <=> b.ferret_rank } unless find_options[:order] - return result - end - - # combine our conditions with those given by user, if any - def self.combine_conditions(conditions, additional_conditions = []) - returning conditions do - if additional_conditions && additional_conditions.any? - cust_opts = (Array === additional_conditions) ? additional_conditions.dup : [ additional_conditions ] - logger.debug "cust_opts: #{cust_opts.inspect}" - conditions.first << " and " << cust_opts.shift - conditions.concat(cust_opts) - end - end - end - - def self.build_field_config(fields) - field_config = {} - case fields - when Array - fields.each { |name| field_config[name] = field_config_for name } - when Hash - fields.each { |name, options| field_config[name] = field_config_for name, options } - else raise InvalidArgumentError.new(":fields option must be Hash or Array") - end if fields - return field_config - end - - def self.ensure_directory(dir) - FileUtils.mkdir_p dir unless (File.directory?(dir) || File.symlink?(dir)) - end - - - # make sure the default index base dir exists. by default, all indexes are created - # under RAILS_ROOT/index/RAILS_ENV - def self.init_index_basedir - index_base = "#{RAILS_ROOT}/index" - @@index_dir = "#{index_base}/#{RAILS_ENV}" - end - - mattr_accessor :index_dir - init_index_basedir - - def self.append_features(base) - super - base.extend(ClassMethods) - end - - # builds a FieldInfos instance for creation of an index - def self.field_infos(index_definition) - # default attributes for fields - fi = Ferret::Index::FieldInfos.new(:store => :no, - :index => :yes, - :term_vector => :no, - :boost => 1.0) - # primary key - fi.add_field(:id, :store => :yes, :index => :untokenized) - # class_name - fi.add_field(:class_name, :store => :yes, :index => :untokenized) - - # other fields - index_definition[:ferret_fields].each_pair do |field, options| - options = options.dup - options.delete :via - options.delete :boost if options[:boost].is_a?(Symbol) # dynamic boost - fi.add_field(field, options) - end - return fi - end - - def self.close_multi_indexes - # close combined index readers, just in case - # this seems to fix a strange test failure that seems to relate to a - # multi_index looking at an old version of the content_base index. - multi_indexes.each_pair do |key, index| - # puts "#{key} -- #{self.name}" - # TODO only close those where necessary (watch inheritance, where - # self.name is base class of a class where key is made from) - index.close #if key =~ /#{self.name}/ - end - multi_indexes.clear - end - - protected - - def self.field_config_for(fieldname, options = {}) - config = DEFAULT_FIELD_OPTIONS.merge options - config[:via] ||= fieldname - config[:term_vector] = :no if config[:index] == :no - return config - end - -end - -# include acts_as_ferret method into ActiveRecord::Base -ActiveRecord::Base.extend ActsAsFerret::ActMethods - diff --git a/vendor/plugins/acts_as_ferret/lib/ar_mysql_auto_reconnect_patch.rb b/vendor/plugins/acts_as_ferret/lib/ar_mysql_auto_reconnect_patch.rb deleted file mode 100644 index 9f5de4a..0000000 --- a/vendor/plugins/acts_as_ferret/lib/ar_mysql_auto_reconnect_patch.rb +++ /dev/null @@ -1,41 +0,0 @@ -# Source: http://pastie.caboo.se/154842 -# -# in /etc/my.cnf on the MySQL server, you can set the interactive-timeout parameter, -# for example, 12 hours = 28800 sec -# interactive-timeout=28800 - -# in ActiveRecord, setting the verification_timeout to something less than -# the interactive-timeout parameter; 14400 sec = 6 hours -ActiveRecord::Base.verification_timeout = 14400 -ActiveRecord::Base.establish_connection - -# Below is a monkey patch for keeping ActiveRecord connections alive. -# http://www.sparecycles.org/2007/7/2/saying-goodbye-to-lost-connections-in-rails - -module ActiveRecord - module ConnectionAdapters - class MysqlAdapter - def execute(sql, name = nil) #:nodoc: - reconnect_lost_connections = true - begin - log(sql, name) { @connection.query(sql) } - rescue ActiveRecord::StatementInvalid => exception - if reconnect_lost_connections and exception.message =~ /(Lost connection to MySQL server during query -|MySQL server has gone away)/ - reconnect_lost_connections = false - reconnect! - retry - elsif exception.message.split(":").first =~ /Packets out of order/ - raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. - Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hash -ing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql -bindings." - else - raise - end - end - end - end - end -end - diff --git a/vendor/plugins/acts_as_ferret/lib/blank_slate.rb b/vendor/plugins/acts_as_ferret/lib/blank_slate.rb deleted file mode 100644 index 3c305c0..0000000 --- a/vendor/plugins/acts_as_ferret/lib/blank_slate.rb +++ /dev/null @@ -1,53 +0,0 @@ -if defined?(BlankSlate) - # Rails 2.x has it already - module ActsAsFerret - class BlankSlate < ::BlankSlate - end - end -else - module ActsAsFerret - # 'backported' for Rails pre 2.0 - # - #-- - # Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org). - # All rights reserved. - - # Permission is granted for use, copying, modification, distribution, - # and distribution of modified versions of this work as long as the - # above copyright notice is included. - #++ - - ###################################################################### - # BlankSlate provides an abstract base class with no predefined - # methods (except for \_\_send__ and \_\_id__). - # BlankSlate is useful as a base class when writing classes that - # depend upon method_missing (e.g. dynamic proxies). - # - class BlankSlate - class << self - # Hide the method named +name+ in the BlankSlate class. Don't - # hide +instance_eval+ or any method beginning with "__". - def hide(name) - if instance_methods.include?(name.to_s) and name !~ /^(__|instance_eval|methods)/ - @hidden_methods ||= {} - @hidden_methods[name.to_sym] = instance_method(name) - undef_method name - end - end - - # Redefine a previously hidden method so that it may be called on a blank - # slate object. - # - # no-op here since we don't hide the methods we reveal where this is - # used in this implementation - def reveal(name) - end - end - - instance_methods.each { |m| hide(m) } - - end - end - -end - diff --git a/vendor/plugins/acts_as_ferret/lib/bulk_indexer.rb b/vendor/plugins/acts_as_ferret/lib/bulk_indexer.rb deleted file mode 100644 index da318c8..0000000 --- a/vendor/plugins/acts_as_ferret/lib/bulk_indexer.rb +++ /dev/null @@ -1,35 +0,0 @@ -module ActsAsFerret - class BulkIndexer - def initialize(args = {}) - @batch_size = args[:batch_size] || 1000 - @logger = args[:logger] - @model = args[:model] - @work_done = 0 - @index = args[:index] - if args[:reindex] - @reindex = true - @model_count = @model.count.to_f - else - @model_count = args[:total] - end - end - - def index_records(records, offset) - batch_time = measure_time { - records.each { |rec| @index.add_document(rec.to_doc, rec.ferret_analyzer) if rec.ferret_enabled?(true) } - }.to_f - @work_done = offset.to_f / @model_count * 100.0 if @model_count > 0 - remaining_time = ( batch_time / @batch_size ) * ( @model_count - offset + @batch_size ) - @logger.info "#{@reindex ? 're' : 'bulk '}index model #{@model.name} : #{'%.2f' % @work_done}% complete : #{'%.2f' % remaining_time} secs to finish" - - end - - def measure_time - t1 = Time.now - yield - Time.now - t1 - end - - end - -end diff --git a/vendor/plugins/acts_as_ferret/lib/class_methods.rb b/vendor/plugins/acts_as_ferret/lib/class_methods.rb deleted file mode 100644 index aea6410..0000000 --- a/vendor/plugins/acts_as_ferret/lib/class_methods.rb +++ /dev/null @@ -1,295 +0,0 @@ -module ActsAsFerret - - module ClassMethods - - # Disables ferret index updates for this model. When a block is given, - # Ferret will be re-enabled again after executing the block. - def disable_ferret - aaf_configuration[:enabled] = false - if block_given? - yield - enable_ferret - end - end - - def enable_ferret - aaf_configuration[:enabled] = true - end - - def ferret_enabled? - aaf_configuration[:enabled] - end - - # rebuild the index from all data stored for this model, and any other - # model classes associated with the same index. - # This is called automatically when no index exists yet. - # - def rebuild_index - aaf_index.rebuild_index - end - - # re-index a number records specified by the given ids. Use for large - # indexing jobs i.e. after modifying a lot of records with Ferret disabled. - # Please note that the state of Ferret (enabled or disabled at class or - # record level) is not checked by this method, so if you need to do so - # (e.g. because of a custom ferret_enabled? implementation), you have to do - # so yourself. - def bulk_index(*ids) - options = Hash === ids.last ? ids.pop : {} - ids = ids.first if ids.size == 1 && ids.first.is_a?(Enumerable) - aaf_index.bulk_index(self.name, ids, options) - end - - # true if our db and table appear to be suitable for the mysql fast batch - # hack (see - # http://weblog.jamisbuck.org/2007/4/6/faking-cursors-in-activerecord) - def use_fast_batches? - if connection.class.name =~ /Mysql/ && primary_key == 'id' && aaf_configuration[:mysql_fast_batches] - logger.info "using mysql specific batched find :all. Turn off with :mysql_fast_batches => false if you encounter problems (i.e. because of non-integer UUIDs in the id column)" - true - end - end - - # Returns all records modified or created after the specified time. - # Used by the rake rebuild task to find models that need to be updated in - # the index after the rebuild finished because they changed while the - # rebuild was running. - # Override if your models don't stick to the created_at/updated_at - # convention. - def records_modified_since(time) - condition = [] - %w(updated_at created_at).each do |col| - condition << "#{col} >= ?" if column_names.include? col - end - if condition.empty? - logger.warn "#{self.name}: Override records_modified_since(time) to keep the index up to date with records changed during rebuild." - [] - else - find :all, :conditions => [ condition.join(' AND '), *([time]*condition.size) ] - end - end - - # runs across all records yielding those to be indexed when the index is rebuilt - def records_for_rebuild(batch_size = 1000) - transaction do - if use_fast_batches? - offset = 0 - while (rows = find :all, :conditions => [ "#{table_name}.id > ?", offset ], :limit => batch_size).any? - offset = rows.last.id - yield rows, offset - end - else - order = "#{primary_key} ASC" # fixes #212 - 0.step(self.count, batch_size) do |offset| - yield find( :all, :limit => batch_size, :offset => offset, :order => order ), offset - end - end - end - end - - # yields the records with the given ids, in batches of batch_size - def records_for_bulk_index(ids, batch_size = 1000) - transaction do - offset = 0 - ids.each_slice(batch_size) do |id_slice| - records = find( :all, :conditions => ["id in (?)", id_slice] ) - #yield records, offset - yield find( :all, :conditions => ["id in (?)", id_slice] ), offset - offset += batch_size - end - end - end - - # Retrieve the index instance for this model class. This can either be a - # LocalIndex, or a RemoteIndex instance. - # - def aaf_index - @index ||= ActsAsFerret::get_index(aaf_configuration[:name]) - end - - # Finds instances by searching the Ferret index. Terms are ANDed by default, use - # OR between terms for ORed queries. Or specify +:or_default => true+ in the - # +:ferret+ options hash of acts_as_ferret. - # - # You may either use the +offset+ and +limit+ options to implement your own - # pagination logic, or use the +page+ and +per_page+ options to use the - # built in pagination support which is compatible with will_paginate's view - # helpers. If +page+ and +per_page+ are given, +offset+ and +limit+ will be - # ignored. - # - # == options: - # page:: page of search results to retrieve - # per_page:: number of search results that are displayed per page - # offset:: first hit to retrieve (useful for paging) - # limit:: number of hits to retrieve, or :all to retrieve - # all results - # lazy:: Array of field names whose contents should be read directly - # from the index. Those fields have to be marked - # +:store => :yes+ in their field options. Give true to get all - # stored fields. Note that if you have a shared index, you have - # to explicitly state the fields you want to fetch, true won't - # work here) - # - # +find_options+ is a hash passed on to active_record's find when - # retrieving the data from db, useful to i.e. prefetch relationships with - # :include or to specify additional filter criteria with :conditions. - # - # This method returns a +SearchResults+ instance, which really is an Array that has - # been decorated with a total_hits attribute holding the total number of hits. - # Additionally, SearchResults is compatible with the pagination helper - # methods of the will_paginate plugin. - # - # Please keep in mind that the number of results delivered might be less than - # +limit+ if you specify any active record conditions that further limit - # the result. Use +limit+ and +offset+ as AR find_options instead. - # +page+ and +per_page+ are supposed to work regardless of any - # +conitions+ present in +find_options+. - def find_with_ferret(q, options = {}, find_options = {}) - aaf_index.register_class(self, {}) - - if respond_to?(:scope) && scope(:find, :conditions) - if find_options[:conditions] - find_options[:conditions] = "(#{find_options[:conditions]}) AND (#{scope(:find, :conditions)})" - else - find_options[:conditions] = scope(:find, :conditions) - end - end - - if options[:per_page] - options[:page] = options[:page] ? options[:page].to_i : 1 - limit = options[:per_page] - offset = (options[:page] - 1) * limit - if find_options[:conditions] - find_options[:limit] = limit - find_options[:offset] = offset - options[:limit] = :all - options.delete :offset - else - # do pagination with ferret - options[:limit] = limit - options[:offset] = offset - end - elsif find_options[:conditions] - find_options[:limit] ||= options.delete(:limit) unless options[:limit] == :all - find_options[:offset] ||= options.delete(:offset) - options[:limit] = :all - end - - total_hits, result = aaf_index.find_records q, options.merge(:models => [self]), find_options - logger.debug "Query: #{q}\ntotal hits: #{total_hits}, results delivered: #{result.size}" - SearchResults.new(result, total_hits, options[:page], options[:per_page]) - end - - - # Returns the total number of hits for the given query - # - # Note that since we don't query the database here, this method won't deliver - # the expected results when used on an AR association. - # - def total_hits(q, options={}) - aaf_index.total_hits(q, options) - end - - # Finds instance model name, ids and scores by contents. - # Useful e.g. if you want to search across models or do not want to fetch - # all result records (yet). - # - # Options are the same as for find_by_contents - # - # A block can be given too, it will be executed with every result: - # find_ids_with_ferret(q, options) do |model, id, score| - # id_array << id - # scores_by_id[id] = score - # end - # NOTE: in case a block is given, only the total_hits value will be returned - # instead of the [total_hits, results] array! - # - def find_ids_with_ferret(q, options = {}, &block) - aaf_index.find_ids(q, options, &block) - end - - - protected - -# def find_records_lazy_or_not(q, options = {}, find_options = {}) -# if options[:lazy] -# logger.warn "find_options #{find_options} are ignored because :lazy => true" unless find_options.empty? -# lazy_find_by_contents q, options -# else -# ar_find_by_contents q, options, find_options -# end -# end -# -# def ar_find_by_contents(q, options = {}, find_options = {}) -# result_ids = {} -# total_hits = find_ids_with_ferret(q, options) do |model, id, score, data| -# # stores ids, index and score of each hit for later ordering of -# # results -# result_ids[id] = [ result_ids.size + 1, score ] -# end -# -# result = ActsAsFerret::retrieve_records( { self.name => result_ids }, find_options ) -# -# # count total_hits via sql when using conditions or when we're called -# # from an ActiveRecord association. -# if find_options[:conditions] or caller.find{ |call| call =~ %r{active_record/associations} } -# # chances are the ferret result count is not our total_hits value, so -# # we correct this here. -# if options[:limit] != :all || options[:page] || options[:offset] || find_options[:limit] || find_options[:offset] -# # our ferret result has been limited, so we need to re-run that -# # search to get the full result set from ferret. -# result_ids = {} -# find_ids_with_ferret(q, options.update(:limit => :all, :offset => 0)) do |model, id, score, data| -# result_ids[id] = [ result_ids.size + 1, score ] -# end -# # Now ask the database for the total size of the final result set. -# total_hits = count_records( { self.name => result_ids }, find_options ) -# else -# # what we got from the database is our full result set, so take -# # it's size -# total_hits = result.length -# end -# end -# -# [ total_hits, result ] -# end -# -# def lazy_find_by_contents(q, options = {}) -# logger.debug "lazy_find_by_contents: #{q}" -# result = [] -# rank = 0 -# total_hits = find_ids_with_ferret(q, options) do |model, id, score, data| -# logger.debug "model: #{model}, id: #{id}, data: #{data}" -# result << FerretResult.new(model, id, score, rank += 1, data) -# end -# [ total_hits, result ] -# end - - - def model_find(model, id, find_options = {}) - model.constantize.find(id, find_options) - end - - -# def count_records(id_arrays, find_options = {}) -# count_options = find_options.dup -# count_options.delete :limit -# count_options.delete :offset -# count = 0 -# id_arrays.each do |model, id_array| -# next if id_array.empty? -# model = model.constantize -# # merge conditions -# conditions = ActsAsFerret::combine_conditions([ "#{model.table_name}.#{model.primary_key} in (?)", id_array.keys ], -# find_options[:conditions]) -# opts = find_options.merge :conditions => conditions -# opts.delete :limit; opts.delete :offset -# count += model.count opts -# end -# count -# end - - end - -end - diff --git a/vendor/plugins/acts_as_ferret/lib/ferret_extensions.rb b/vendor/plugins/acts_as_ferret/lib/ferret_extensions.rb deleted file mode 100644 index dbc0ad7..0000000 --- a/vendor/plugins/acts_as_ferret/lib/ferret_extensions.rb +++ /dev/null @@ -1,115 +0,0 @@ -module Ferret - - module Analysis - - # = PerFieldAnalyzer - # - # This PerFieldAnalyzer is a workaround to a memory leak in - # ferret 0.11.4. It does basically do the same as the original - # Ferret::Analysis::PerFieldAnalyzer, but without the leak :) - # - # http://ferret.davebalmain.com/api/classes/Ferret/Analysis/PerFieldAnalyzer.html - # - # Thanks to Ben from omdb.org for tracking this down and creating this - # workaround. - # You can read more about the issue there: - # http://blog.omdb-beta.org/2007/7/29/tracking-down-a-memory-leak-in-ferret-0-11-4 - class PerFieldAnalyzer < ::Ferret::Analysis::Analyzer - def initialize( default_analyzer = StandardAnalyzer.new ) - @analyzers = {} - @default_analyzer = default_analyzer - end - - def add_field( field, analyzer ) - @analyzers[field] = analyzer - end - alias []= add_field - - def token_stream(field, string) - @analyzers.has_key?(field) ? @analyzers[field].token_stream(field, string) : - @default_analyzer.token_stream(field, string) - end - end - end - - class Index::Index - attr_accessor :batch_size, :logger - - def index_models(models) - models.each { |model| index_model model } - flush - optimize - close - ActsAsFerret::close_multi_indexes - end - - def index_model(model) - bulk_indexer = ActsAsFerret::BulkIndexer.new(:batch_size => @batch_size, :logger => logger, - :model => model, :index => self, :reindex => true) - logger.info "reindexing model #{model.name}" - - model.records_for_rebuild(@batch_size) do |records, offset| - bulk_indexer.index_records(records, offset) - end - end - - def bulk_index(model, ids, options = {}) - options.reverse_merge! :optimize => true - orig_flush = @auto_flush - @auto_flush = false - bulk_indexer = ActsAsFerret::BulkIndexer.new(:batch_size => @batch_size, :logger => logger, - :model => model, :index => self, :total => ids.size) - model.records_for_bulk_index(ids, @batch_size) do |records, offset| - logger.debug "#{model} bulk indexing #{records.size} at #{offset}" - bulk_indexer.index_records(records, offset) - end - logger.info 'finishing bulk index...' - flush - if options[:optimize] - logger.info 'optimizing...' - optimize - end - @auto_flush = orig_flush - end - - end - - # add marshalling support to SortFields - class Search::SortField - def _dump(depth) - to_s - end - - def self._load(string) - case string - when /!/ : Ferret::Search::SortField::DOC_ID_REV - when // : Ferret::Search::SortField::DOC_ID - when '!' : Ferret::Search::SortField::SCORE_REV - when '' : Ferret::Search::SortField::SCORE - when /^(\w+):<(\w+)>(!)?$/ : new($1.to_sym, :type => $2.to_sym, :reverse => !$3.nil?) - else raise "invalid value: #{string}" - end - end - end - - # add marshalling support to Sort - class Search::Sort - def _dump(depth) - to_s - end - - def self._load(string) - # we exclude the last sorting as it is appended by new anyway - if string =~ /^Sort\[(.*?)((!)?)?\]$/ - sort_fields = $1.split(',').map do |value| - value.strip! - Ferret::Search::SortField._load value unless value.blank? - end - new sort_fields.compact - else - raise "invalid value: #{string}" - end - end - end - -end diff --git a/vendor/plugins/acts_as_ferret/lib/ferret_find_methods.rb b/vendor/plugins/acts_as_ferret/lib/ferret_find_methods.rb deleted file mode 100644 index c2c8881..0000000 --- a/vendor/plugins/acts_as_ferret/lib/ferret_find_methods.rb +++ /dev/null @@ -1,118 +0,0 @@ -module ActsAsFerret - # Ferret search logic common to single-class indexes, shared indexes and - # multi indexes. - module FerretFindMethods - - def find_records(q, options = {}, ar_options = {}) - if options[:lazy] - logger.warn "find_options #{ar_options} are ignored because :lazy => true" unless ar_options.empty? - lazy_find q, options - else - ar_find q, options, ar_options - end - end - - def lazy_find(q, options = {}) - logger.debug "lazy_find: #{q}" - result = [] - rank = 0 - total_hits = find_ids(q, options) do |model, id, score, data| - logger.debug "model: #{model}, id: #{id}, data: #{data}" - result << FerretResult.new(model, id, score, rank += 1, data) - end - [ total_hits, result ] - end - - def ar_find(q, options = {}, ar_options = {}) - total_hits, id_arrays = find_id_model_arrays q, options - result = ActsAsFerret::retrieve_records(id_arrays, ar_options) - - # count total_hits via sql when using conditions, multiple models, or when we're called - # from an ActiveRecord association. - if id_arrays.size > 1 or ar_options[:conditions] - # chances are the ferret result count is not our total_hits value, so - # we correct this here. - if options[:limit] != :all || options[:page] || options[:offset] || ar_options[:limit] || ar_options[:offset] - # our ferret result has been limited, so we need to re-run that - # search to get the full result set from ferret. - new_th, id_arrays = find_id_model_arrays( q, options.merge(:limit => :all, :offset => 0) ) - # Now ask the database for the total size of the final result set. - total_hits = count_records( id_arrays, ar_options ) - else - # what we got from the database is our full result set, so take - # it's size - total_hits = result.length - end - end - [ total_hits, result ] - end - - def count_records(id_arrays, ar_options = {}) - count_options = ar_options.dup - count_options.delete :limit - count_options.delete :offset - count = 0 - id_arrays.each do |model, id_array| - next if id_array.empty? - model = model.constantize - # merge conditions - conditions = ActsAsFerret::conditions_for_model model, ar_options[:conditions] - count_options[:conditions] = ActsAsFerret::combine_conditions([ "#{model.table_name}.#{model.primary_key} in (?)", id_array.keys ], conditions) - count += model.count count_options - end - count - end - - def find_id_model_arrays(q, options) - id_arrays = {} - rank = 0 - total_hits = find_ids(q, options) do |model, id, score, data| - id_arrays[model] ||= {} - id_arrays[model][id] = [ rank += 1, score ] - end - [total_hits, id_arrays] - end - - # Queries the Ferret index to retrieve model class, id, score and the - # values of any fields stored in the index for each hit. - # If a block is given, these are yielded and the number of total hits is - # returned. Otherwise [total_hits, result_array] is returned. - def find_ids(query, options = {}) - - result = [] - stored_fields = determine_stored_fields options - - q = process_query(query, options) - q = scope_query_to_models q, options[:models] #if shared? - logger.debug "query: #{query}\n-->#{q}" - s = searcher - total_hits = s.search_each(q, options) do |hit, score| - doc = s[hit] - model = doc[:class_name] - # fetch stored fields if lazy loading - data = extract_stored_fields(doc, stored_fields) - if block_given? - yield model, doc[:id], score, data - else - result << { :model => model, :id => doc[:id], :score => score, :data => data } - end - end - #logger.debug "id_score_model array: #{result.inspect}" - return block_given? ? total_hits : [total_hits, result] - end - - def scope_query_to_models(query, models) - return query if models.nil? or models == :all - models = [ models ] if Class === models - q = Ferret::Search::BooleanQuery.new - q.add_query(query, :must) - model_query = Ferret::Search::BooleanQuery.new - models.each do |model| - model_query.add_query(Ferret::Search::TermQuery.new(:class_name, model.name), :should) - end - q.add_query(model_query, :must) - return q - end - - end -end diff --git a/vendor/plugins/acts_as_ferret/lib/ferret_result.rb b/vendor/plugins/acts_as_ferret/lib/ferret_result.rb deleted file mode 100644 index 76ab421..0000000 --- a/vendor/plugins/acts_as_ferret/lib/ferret_result.rb +++ /dev/null @@ -1,53 +0,0 @@ -module ActsAsFerret - - # mixed into the FerretResult and AR classes calling acts_as_ferret - module ResultAttributes - # holds the score this record had when it was found via - # acts_as_ferret - attr_accessor :ferret_score - - attr_accessor :ferret_rank - end - - class FerretResult < ActsAsFerret::BlankSlate - include ResultAttributes - attr_accessor :id - reveal :methods - - def initialize(model, id, score, rank, data = {}) - @model = model.constantize - @id = id - @ferret_score = score - @ferret_rank = rank - @data = data - @use_record = false - end - - def inspect - "# 'localhost', - 'port' => '9009', - 'cf' => "#{RAILS_ROOT}/config/ferret_server.yml", - 'pid_file' => "#{RAILS_ROOT}/log/ferret_server.pid", - 'log_file' => "#{RAILS_ROOT}/log/ferret_server.log", - 'log_level' => 'debug', - 'socket' => nil, - 'script' => nil - } - - ################################################################################ - # load the configuration file and apply default settings - def initialize (file=DEFAULTS['cf']) - @everything = YAML.load(ERB.new(IO.read(file)).result) - raise "malformed ferret server config" unless @everything.is_a?(Hash) - @config = DEFAULTS.merge(@everything[RAILS_ENV] || {}) - if @everything[RAILS_ENV] - @config['uri'] = socket.nil? ? "druby://#{host}:#{port}" : "drbunix:#{socket}" - end - end - - ################################################################################ - # treat the keys of the config data as methods - def method_missing (name, *args) - @config.has_key?(name.to_s) ? @config[name.to_s] : super - end - - end - - ################################################################################# - # This class acts as a drb server listening for indexing and - # search requests from models declared to 'acts_as_ferret :remote => true' - # - # Usage: - # - modify RAILS_ROOT/config/ferret_server.yml to suit your needs. - # - environments for which no section in the config file exists will use - # the index locally (good for unit tests/development mode) - # - run script/ferret_server to start the server: - # script/ferret_server -e production start - # - to stop the server run - # script/ferret_server -e production stop - # - class Server - - ################################################################################# - # FIXME include detection of OS and include the correct file - require 'unix_daemon' - include(ActsAsFerret::Remote::UnixDaemon) - - - ################################################################################ - cattr_accessor :running - - ################################################################################ - def initialize - ActiveRecord::Base.allow_concurrency = true - require 'ar_mysql_auto_reconnect_patch' - @cfg = ActsAsFerret::Remote::Config.new - ActiveRecord::Base.logger = @logger = Logger.new(@cfg.log_file) - ActiveRecord::Base.logger.level = Logger.const_get(@cfg.log_level.upcase) rescue Logger::DEBUG - if @cfg.script - path = File.join(RAILS_ROOT, @cfg.script) - load path - @logger.info "loaded custom startup script from #{path}" - end - end - - ################################################################################ - # start the server as a daemon process - def start - raise "ferret_server not configured for #{RAILS_ENV}" unless (@cfg.uri rescue nil) - platform_daemon { run_drb_service } - end - - ################################################################################ - # run the server and block until it exits - def run - raise "ferret_server not configured for #{RAILS_ENV}" unless (@cfg.uri rescue nil) - run_drb_service - end - - def run_drb_service - $stdout.puts("starting ferret server...") - self.class.running = true - DRb.start_service(@cfg.uri, self) - DRb.thread.join - rescue Exception => e - @logger.error(e.to_s) - raise - end - - ################################################################################# - # handles all incoming method calls, and sends them on to the correct local index - # instance. - # - # Calls are not queued, so this will block until the call returned. - # - def method_missing(name, *args) - @logger.debug "\#method_missing(#{name.inspect}, #{args.inspect})" - - - index_name = args.shift - index = if name.to_s =~ /^multi_(.+)/ - name = $1 - ActsAsFerret::multi_index(index_name) - else - ActsAsFerret::get_index(index_name) - end - - if index.nil? - @logger.error "\#index with name #{index_name} not found in call to #{name} with args #{args.inspect}" - raise ActsAsFerret::IndexNotDefined.new(index_name) - end - - - # TODO find another way to implement the reconnection logic (maybe in - # local_index or class_methods) - # reconnect_when_needed(clazz) do - - # using respond_to? here so we not have to catch NoMethodError - # which would silently catch those from deep inside the indexing - # code, too... - - if index.respond_to?(name) - index.send name, *args - # TODO check where we need this: - #elsif clazz.respond_to?(name) - # @logger.debug "no luck, trying to call class method instead" - # clazz.send name, *args - else - raise NoMethodError.new("method #{name} not supported by DRb server") - end - rescue => e - @logger.error "ferret server error #{$!}\n#{$!.backtrace.join "\n"}" - raise e - end - - def register_class(class_name) - @logger.debug "############ registerclass #{class_name}" - class_name.constantize - @logger.debug "index for class #{class_name}: #{ActsAsFerret::ferret_indexes[class_name.underscore.to_sym]}" - - end - - # make sure we have a versioned index in place, building one if necessary - def ensure_index_exists(index_name) - @logger.debug "DRb server: ensure_index_exists for index #{index_name}" - definition = ActsAsFerret::get_index(index_name).index_definition - dir = definition[:index_dir] - unless File.directory?(dir) && File.file?(File.join(dir, 'segments')) && dir =~ %r{/\d+(_\d+)?$} - rebuild_index(index_name) - end - end - - # disconnects the db connection for the class specified by class_name - # used only in unit tests to check the automatic reconnection feature - def db_disconnect!(class_name) - with_class class_name do |clazz| - clazz.connection.disconnect! - end - end - - # hides LocalIndex#rebuild_index to implement index versioning - def rebuild_index(index_name) - definition = ActsAsFerret::get_index(index_name).index_definition.dup - models = definition[:registered_models] - index = new_index_for(definition) - # TODO fix reconnection stuff - # reconnect_when_needed(clazz) do - # @logger.debug "DRb server: rebuild index for class(es) #{models.inspect} in #{index.options[:path]}" - index.index_models models - # end - new_version = File.join definition[:index_base_dir], Time.now.utc.strftime('%Y%m%d%H%M%S') - # create a unique directory name (needed for unit tests where - # multiple rebuilds per second may occur) - if File.exists?(new_version) - i = 0 - i+=1 while File.exists?("#{new_version}_#{i}") - new_version << "_#{i}" - end - - File.rename index.options[:path], new_version - ActsAsFerret::change_index_dir index_name, new_version - end - - - protected - - def reconnect_when_needed(clazz) - retried = false - begin - yield - rescue ActiveRecord::StatementInvalid => e - if e.message =~ /MySQL server has gone away/ - if retried - raise e - else - @logger.info "StatementInvalid caught, trying to reconnect..." - clazz.connection.reconnect! - retried = true - retry - end - else - @logger.error "StatementInvalid caught, but unsure what to do with it: #{e}" - raise e - end - end - end - - def new_index_for(index_definition) - ferret_cfg = index_definition[:ferret].dup - ferret_cfg.update :auto_flush => false, - :create => true, - :field_infos => ActsAsFerret::field_infos(index_definition), - :path => File.join(index_definition[:index_base_dir], 'rebuild') - returning Ferret::Index::Index.new(ferret_cfg) do |i| - i.batch_size = index_definition[:reindex_batch_size] - i.logger = @logger - end - end - - end - end -end diff --git a/vendor/plugins/acts_as_ferret/lib/index.rb b/vendor/plugins/acts_as_ferret/lib/index.rb deleted file mode 100644 index a779bf1..0000000 --- a/vendor/plugins/acts_as_ferret/lib/index.rb +++ /dev/null @@ -1,99 +0,0 @@ -module ActsAsFerret - - class IndexLogger - def initialize(logger, name) - @logger = logger - @index_name = name - end - %w(debug info warn error).each do |m| - define_method(m) do |message| - @logger.send m, "[#{@index_name}] #{message}" - end - question = :"#{m}?" - define_method(question) do - @logger.send question - end - end - end - - # base class for local and remote indexes - class AbstractIndex - include FerretFindMethods - - attr_reader :logger, :index_name, :index_definition, :registered_models_config - def initialize(index_definition) - @index_definition = index_definition - @registered_models_config = {} - @index_name = index_definition[:name] - @logger = IndexLogger.new(ActsAsFerret::logger, @index_name) - end - - # TODO allow for per-class field configuration (i.e. different via, boosts - # for the same field among different models) - def register_class(clazz, options = {}) - logger.info "register class #{clazz} with index #{index_name}" - - if force = options.delete(:force_re_registration) - index_definition[:registered_models].delete(clazz) - end - - if index_definition[:registered_models].map(&:name).include?(clazz.name) - logger.info("refusing re-registration of class #{clazz}") - else - index_definition[:registered_models] << clazz - @registered_models_config[clazz] = options - - # merge fields from this acts_as_ferret call with predefined fields - already_defined_fields = index_definition[:ferret_fields] - field_config = ActsAsFerret::build_field_config options[:fields] - field_config.update ActsAsFerret::build_field_config( options[:additional_fields] ) - field_config.each do |field, config| - if already_defined_fields.has_key?(field) - logger.info "ignoring redefinition of ferret field #{field}" if shared? - else - already_defined_fields[field] = config - logger.info "adding new field #{field} from class #{clazz.name} to index #{index_name}" - end - end - - # update default field list to be used by the query parser, unless it - # was explicitly given by user. - # - # It will include all content fields *not* marked as :untokenized. - # This fixes the otherwise failing CommentTest#test_stopwords. Basically - # this means that by default only tokenized fields (which all fields are - # by default) will be searched. If you want to search inside the contents - # of an untokenized field, you'll have to explicitly specify it in your - # query. - unless index_definition[:user_default_field] - # grab all tokenized fields - ferret_fields = index_definition[:ferret_fields] - index_definition[:ferret][:default_field] = ferret_fields.keys.select do |field| - ferret_fields[field][:index] != :untokenized - end - logger.info "default field list for index #{index_name}: #{index_definition[:ferret][:default_field].inspect}" - end - end - - return index_definition - end - - # true if this index is used by more than one model class - def shared? - index_definition[:registered_models].size > 1 - end - - # Switches the index to a new index directory. - # Used by the DRb server when switching to a new index version. - def change_index_dir(new_dir) - logger.debug "[#{index_name}] changing index dir to #{new_dir}" - index_definition[:index_dir] = index_definition[:ferret][:path] = new_dir - reopen! - logger.debug "[#{index_name}] index dir is now #{new_dir}" - end - - protected - - end - -end diff --git a/vendor/plugins/acts_as_ferret/lib/instance_methods.rb b/vendor/plugins/acts_as_ferret/lib/instance_methods.rb deleted file mode 100644 index 8292b86..0000000 --- a/vendor/plugins/acts_as_ferret/lib/instance_methods.rb +++ /dev/null @@ -1,165 +0,0 @@ -module ActsAsFerret #:nodoc: - - module InstanceMethods - include ResultAttributes - - # Returns an array of strings with the matches highlighted. The +query+ can - # either be a String or a Ferret::Search::Query object. - # - # === Options - # - # field:: field to take the content from. This field has - # to have it's content stored in the index - # (:store => :yes in your call to aaf). If not - # given, all stored fields are searched, and the - # highlighted content found in all of them is returned. - # set :highlight => :no in the field options to - # avoid highlighting of contents from a :stored field. - # excerpt_length:: Default: 150. Length of excerpt to show. Highlighted - # terms will be in the centre of the excerpt. - # num_excerpts:: Default: 2. Number of excerpts to return. - # pre_tag:: Default: "". Tag to place to the left of the - # match. - # post_tag:: Default: "". This tag should close the - # +:pre_tag+. - # ellipsis:: Default: "...". This is the string that is appended - # at the beginning and end of excerpts (unless the - # excerpt hits the start or end of the field. You'll - # probably want to change this to a Unicode elipsis - # character. - def highlight(query, options = {}) - self.class.aaf_index.highlight(self.send(self.class.primary_key), self.class.name, query, options) - end - - # re-eneable ferret indexing for this instance after a call to #disable_ferret - def enable_ferret - @ferret_disabled = nil - end - alias ferret_enable enable_ferret # compatibility - - # returns true if ferret indexing is enabled for this record. - # - # The optional is_bulk_index parameter will be true if the method is called - # by rebuild_index or bulk_index, and false otherwise. - # - # If is_bulk_index is true, the class level ferret_enabled state will be - # ignored by this method (per-instance ferret_enabled checks however will - # take place, so if you override this method to forbid indexing of certain - # records you're still safe). - def ferret_enabled?(is_bulk_index = false) - @ferret_disabled.nil? && (is_bulk_index || self.class.ferret_enabled?) && (aaf_configuration[:if].nil? || aaf_configuration[:if].call(self)) - end - - # Returns the analyzer to use when adding this record to the index. - # - # Override to return a specific analyzer for any record that is to be - # indexed, i.e. specify a different analyzer based on language. Returns nil - # by default so the global analyzer (specified with the acts_as_ferret - # call) is used. - def ferret_analyzer - nil - end - - # Disable Ferret for this record for a specified amount of time. ::once will - # disable Ferret for the next call to #save (this is the default), ::always - # will do so for all subsequent calls. - # - # Note that this will turn off only the create and update hooks, but not the - # destroy hook. I think that's reasonable, if you think the opposite, please - # tell me. - # - # To manually trigger reindexing of a record after you're finished modifying - # it, you can call #ferret_update directly instead of #save (remember to - # enable ferret again before). - # - # When given a block, this will be executed without any ferret indexing of - # this object taking place. The optional argument in this case can be used - # to indicate if the object should be indexed after executing the block - # (::index_when_finished). Automatic Ferret indexing of this object will be - # turned on after the block has been executed. If passed ::index_when_true, - # the index will only be updated if the block evaluated not to false or nil. - # - def disable_ferret(option = :once) - if block_given? - @ferret_disabled = :always - result = yield - ferret_enable - ferret_update if option == :index_when_finished || (option == :index_when_true && result) - result - elsif [:once, :always].include?(option) - @ferret_disabled = option - else - raise ArgumentError.new("Invalid Argument #{option}") - end - end - - # add to index - def ferret_create - if ferret_enabled? - logger.debug "ferret_create/update: #{self.class.name} : #{self.id}" - self.class.aaf_index << self - else - ferret_enable if @ferret_disabled == :once - end - true # signal success to AR - end - alias :ferret_update :ferret_create - - - # remove from index - def ferret_destroy - logger.debug "ferret_destroy: #{self.class.name} : #{self.id}" - begin - self.class.aaf_index.remove self.id, self.class.name - rescue - logger.warn("Could not find indexed value for this object: #{$!}\n#{$!.backtrace}") - end - true # signal success to AR - end - - # turn this instance into a ferret document (which basically is a hash of - # fieldname => value pairs) - def to_doc - logger.debug "creating doc for class: #{self.class.name}, id: #{self.id}" - returning Ferret::Document.new do |doc| - # store the id and class name of each item - doc[:id] = self.id - doc[:class_name] = self.class.name - - # iterate through the fields and add them to the document - aaf_configuration[:defined_fields].each_pair do |field, config| - doc[field] = self.send("#{field}_to_ferret") unless config[:ignore] - end - if aaf_configuration[:boost] - if self.respond_to?(aaf_configuration[:boost]) - boost = self.send aaf_configuration[:boost] - doc.boost = boost.to_i if boost - else - logger.error "boost option should point to an instance method: #{aaf_configuration[:boost]}" - end - end - end - end - - def document_number - self.class.aaf_index.document_number(id, self.class.name) - end - - def query_for_record - self.class.aaf_index.query_for_record(id, self.class.name) - end - - def content_for_field_name(field, via = field, dynamic_boost = nil) - return nil if field.to_sym == :type - field_data = self.send(via) || self.instance_variable_get("@#{via}") - if (dynamic_boost && boost_value = self.send(dynamic_boost)) - field_data = Ferret::Field.new(field_data) - field_data.boost = boost_value.to_i - end - field_data - end - - - end - -end diff --git a/vendor/plugins/acts_as_ferret/lib/local_index.rb b/vendor/plugins/acts_as_ferret/lib/local_index.rb deleted file mode 100644 index e7e392e..0000000 --- a/vendor/plugins/acts_as_ferret/lib/local_index.rb +++ /dev/null @@ -1,199 +0,0 @@ -module ActsAsFerret - class LocalIndex < AbstractIndex - include MoreLikeThis::IndexMethods - - def initialize(index_name) - super - ensure_index_exists - end - - def reopen! - logger.debug "reopening index at #{index_definition[:ferret][:path]}" - close - ferret_index - end - - # The 'real' Ferret Index instance - def ferret_index - ensure_index_exists - returning @ferret_index ||= Ferret::Index::Index.new(index_definition[:ferret]) do - @ferret_index.batch_size = index_definition[:reindex_batch_size] - @ferret_index.logger = logger - end - end - - # Checks for the presence of a segments file in the index directory - # Rebuilds the index if none exists. - def ensure_index_exists - #logger.debug "LocalIndex: ensure_index_exists at #{index_definition[:index_dir]}" - unless File.file? "#{index_definition[:index_dir]}/segments" - ActsAsFerret::ensure_directory(index_definition[:index_dir]) - rebuild_index - end - end - - # Closes the underlying index instance - def close - @ferret_index.close if @ferret_index - rescue StandardError - # is raised when index already closed - ensure - @ferret_index = nil - end - - # rebuilds the index from all records of the model classes associated with this index - def rebuild_index - models = index_definition[:registered_models] - logger.debug "rebuild index with models: #{models.inspect}" - close - index = Ferret::Index::Index.new(index_definition[:ferret].dup.update(:auto_flush => false, - :field_infos => ActsAsFerret::field_infos(index_definition), - :create => true)) - index.batch_size = index_definition[:reindex_batch_size] - index.logger = logger - index.index_models models - reopen! - end - - def bulk_index(class_name, ids, options) - ferret_index.bulk_index(class_name.constantize, ids, options) - end - - # Parses the given query string into a Ferret Query object. - def process_query(query, options = {}) - return query unless String === query - ferret_index.synchronize do - if options[:analyzer] - # use per-query analyzer if present - qp = Ferret::QueryParser.new ferret_index.instance_variable_get('@options').merge(options) - reader = ferret_index.reader - qp.fields = - reader.fields unless options[:all_fields] || options[:fields] - qp.tokenized_fields = - reader.tokenized_fields unless options[:tokenized_fields] - return qp.parse query - else - # work around ferret bug in #process_query (doesn't ensure the - # reader is open) - ferret_index.send(:ensure_reader_open) - return ferret_index.process_query(query) - end - end - end - - # Total number of hits for the given query. - def total_hits(query, options = {}) - ferret_index.search(query, options).total_hits - end - - def searcher - ferret_index - end - - - ###################################### - # methods working on a single record - # called from instance_methods, here to simplify interfacing with the - # remote ferret server - # TODO having to pass id and class_name around like this isn't nice - ###################################### - - # add record to index - # record may be the full AR object, a Ferret document instance or a Hash - def add(record, analyzer = nil) - unless Hash === record || Ferret::Document === record - analyzer = record.ferret_analyzer - record = record.to_doc - end - ferret_index.add_document(record, analyzer) - end - alias << add - - # delete record from index - def remove(id, class_name) - ferret_index.query_delete query_for_record(id, class_name) - end - - # highlight search terms for the record with the given id. - def highlight(id, class_name, query, options = {}) - logger.debug("highlight: #{class_name} / #{id} query: #{query}") - options.reverse_merge! :num_excerpts => 2, :pre_tag => '', :post_tag => '' - highlights = [] - ferret_index.synchronize do - doc_num = document_number(id, class_name) - - if options[:field] - highlights << ferret_index.highlight(query, doc_num, options) - else - query = process_query(query) # process only once - index_definition[:ferret_fields].each_pair do |field, config| - next if config[:store] == :no || config[:highlight] == :no - options[:field] = field - highlights << ferret_index.highlight(query, doc_num, options) - end - end - end - return highlights.compact.flatten[0..options[:num_excerpts]-1] - end - - # retrieves the ferret document number of the record with the given id. - def document_number(id, class_name) - hits = ferret_index.search(query_for_record(id, class_name)) - return hits.hits.first.doc if hits.total_hits == 1 - raise "cannot determine document number for class #{class_name} / primary key: #{id}\nresult was: #{hits.inspect}" - end - - # build a ferret query matching only the record with the given id - # the class name only needs to be given in case of a shared index configuration - def query_for_record(id, class_name = nil) - if shared? - raise InvalidArgumentError.new("shared index needs class_name argument") if class_name.nil? - returning bq = Ferret::Search::BooleanQuery.new do - bq.add_query(Ferret::Search::TermQuery.new(:id, id.to_s), :must) - bq.add_query(Ferret::Search::TermQuery.new(:class_name, class_name), :must) - end - else - Ferret::Search::TermQuery.new(:id, id.to_s) - end - end - - - - def determine_stored_fields(options = {}) - stored_fields = options[:lazy] - if stored_fields && !(Array === stored_fields) - stored_fields = index_definition[:ferret_fields].select { |field, config| config[:store] == :yes }.map(&:first) - end - logger.debug "stored_fields: #{stored_fields.inspect}" - return stored_fields - end - - # loads data for fields declared as :lazy from the Ferret document - def extract_stored_fields(doc, stored_fields) - fields = index_definition[:ferret_fields] - data = {} - logger.debug "extracting stored fields #{stored_fields.inspect} from document #{doc[:class_name]} / #{doc[:id]}" - stored_fields.each do |field| - if field_cfg = fields[field] - data[field_cfg[:via]] = doc[field] - end - end if stored_fields - logger.debug "done: #{data.inspect}" - return data - end - - protected - - # returns a MultiIndex instance operating on a MultiReader - #def multi_index(model_classes) - # model_classes.map!(&:constantize) if String === model_classes.first - # model_classes.sort! { |a, b| a.name <=> b.name } - # key = model_classes.inject("") { |s, clazz| s + clazz.name } - # multi_config = index_definition[:ferret].dup - # multi_config.delete :default_field # we don't want the default field list of *this* class for multi_searching - # ActsAsFerret::multi_indexes[key] ||= MultiIndex.new(model_classes, multi_config) - #end - - end - -end diff --git a/vendor/plugins/acts_as_ferret/lib/more_like_this.rb b/vendor/plugins/acts_as_ferret/lib/more_like_this.rb deleted file mode 100644 index 0d16a56..0000000 --- a/vendor/plugins/acts_as_ferret/lib/more_like_this.rb +++ /dev/null @@ -1,217 +0,0 @@ -module ActsAsFerret #:nodoc: - - module MoreLikeThis - - module InstanceMethods - - # returns other instances of this class, which have similar contents - # like this one. Basically works like this: find out n most interesting - # (i.e. characteristic) terms from this document, and then build a - # query from those which is run against the whole index. Which terms - # are interesting is decided on variour criteria which can be - # influenced by the given options. - # - # The algorithm used here is a quite straight port of the MoreLikeThis class - # from Apache Lucene. - # - # options are: - # :field_names : Array of field names to use for similarity search (mandatory) - # :min_term_freq => 2, # Ignore terms with less than this frequency in the source doc. - # :min_doc_freq => 5, # Ignore words which do not occur in at least this many docs - # :min_word_length => nil, # Ignore words shorter than this length (longer words tend to - # be more characteristic for the document they occur in). - # :max_word_length => nil, # Ignore words if greater than this len. - # :max_query_terms => 25, # maximum number of terms in the query built - # :max_num_tokens => 5000, # maximum number of tokens to examine in a single field - # :boost => false, # when true, a boost according to the relative score of - # a term is applied to this Term's TermQuery. - # :similarity => 'DefaultAAFSimilarity' # the similarity implementation to use (the default - # equals Ferret's internal similarity implementation) - # :analyzer => 'Ferret::Analysis::StandardAnalyzer' # class name of the analyzer to use - # :append_to_query => nil # proc taking a query object as argument, which will be called after generating the query. can be used to further manipulate the query used to find related documents, i.e. to constrain the search to a given class in single table inheritance scenarios - # ferret_options : Ferret options handed over to find_by_contents (i.e. for limits and sorting) - # ar_options : options handed over to find_by_contents for AR scoping - def more_like_this(options = {}, ferret_options = {}, ar_options = {}) - options = { - :field_names => nil, # Default field names - :min_term_freq => 2, # Ignore terms with less than this frequency in the source doc. - :min_doc_freq => 5, # Ignore words which do not occur in at least this many docs - :min_word_length => 0, # Ignore words if less than this len. Default is not to ignore any words. - :max_word_length => 0, # Ignore words if greater than this len. Default is not to ignore any words. - :max_query_terms => 25, # maximum number of terms in the query built - :max_num_tokens => 5000, # maximum number of tokens to analyze when analyzing contents - :boost => false, - :similarity => 'ActsAsFerret::MoreLikeThis::DefaultAAFSimilarity', # class name of the similarity implementation to use - :analyzer => 'Ferret::Analysis::StandardAnalyzer', # class name of the analyzer to use - :append_to_query => nil, - :base_class => self.class # base class to use for querying, useful in STI scenarios where BaseClass.find_by_contents can be used to retrieve results from other classes, too - }.update(options) - #index.search_each('id:*') do |doc, score| - # puts "#{doc} == #{index[doc][:description]}" - #end - clazz = options[:base_class] - options[:base_class] = clazz.name - query = clazz.aaf_index.build_more_like_this_query(self.id, self.class.name, options) - options[:append_to_query].call(query) if options[:append_to_query] - clazz.find_with_ferret(query, ferret_options, ar_options) - end - - end - - module IndexMethods - - # TODO to allow morelikethis for unsaved records, we have to give the - # unsaved record's data to this method. check how this will work out - # via drb... - def build_more_like_this_query(id, class_name, options) - [:similarity, :analyzer].each { |sym| options[sym] = options[sym].constantize.new } - ferret_index.synchronize do # avoid that concurrent writes close our reader - ferret_index.send(:ensure_reader_open) - reader = ferret_index.send(:reader) - term_freq_map = retrieve_terms(id, class_name, reader, options) - priority_queue = create_queue(term_freq_map, reader, options) - create_query(id, class_name, priority_queue, options) - end - end - - protected - - def create_query(id, class_name, priority_queue, options={}) - query = Ferret::Search::BooleanQuery.new - qterms = 0 - best_score = nil - while(cur = priority_queue.pop) - term_query = Ferret::Search::TermQuery.new(cur.field, cur.word) - - if options[:boost] - # boost term according to relative score - # TODO untested - best_score ||= cur.score - term_query.boost = cur.score / best_score - end - begin - query.add_query(term_query, :should) - rescue Ferret::Search::BooleanQuery::TooManyClauses - break - end - qterms += 1 - break if options[:max_query_terms] > 0 && qterms >= options[:max_query_terms] - end - # exclude the original record - query.add_query(query_for_record(id, class_name), :must_not) - return query - end - - - - # creates a term/term_frequency map for terms from the fields - # given in options[:field_names] - def retrieve_terms(id, class_name, reader, options) - raise "more_like_this atm only works on saved records" if id.nil? - document_number = document_number(id, class_name) rescue nil - field_names = options[:field_names] - max_num_tokens = options[:max_num_tokens] - term_freq_map = Hash.new(0) - doc = nil - record = nil - field_names.each do |field| - #puts "field: #{field}" - term_freq_vector = reader.term_vector(document_number, field) if document_number - #if false - if term_freq_vector - # use stored term vector - # puts 'using stored term vector' - term_freq_vector.terms.each do |term| - term_freq_map[term.text] += term.positions.size unless noise_word?(term.text, options) - end - else - # puts 'no stored term vector' - # no term vector stored, but we have stored the contents in the index - # -> extract terms from there - content = nil - if document_number - doc = reader[document_number] - content = doc[field] - end - unless content - # no term vector, no stored content, so try content from this instance - record ||= options[:base_class].constantize.find(id) - content = record.content_for_field_name(field.to_s) - end - puts "have doc: #{doc[:id]} with #{field} == #{content}" - token_count = 0 - - ts = options[:analyzer].token_stream(field, content) - while token = ts.next - break if (token_count+=1) > max_num_tokens - next if noise_word?(token.text, options) - term_freq_map[token.text] += 1 - end - end - end - term_freq_map - end - - # create an ordered(by score) list of word,fieldname,score - # structures - def create_queue(term_freq_map, reader, options) - pq = Array.new(term_freq_map.size) - - similarity = options[:similarity] - num_docs = reader.num_docs - term_freq_map.each_pair do |word, tf| - # filter out words that don't occur enough times in the source - next if options[:min_term_freq] && tf < options[:min_term_freq] - - # go through all the fields and find the largest document frequency - top_field = options[:field_names].first - doc_freq = 0 - options[:field_names].each do |field_name| - freq = reader.doc_freq(field_name, word) - if freq > doc_freq - top_field = field_name - doc_freq = freq - end - end - # filter out words that don't occur in enough docs - next if options[:min_doc_freq] && doc_freq < options[:min_doc_freq] - next if doc_freq == 0 # index update problem ? - - idf = similarity.idf(doc_freq, num_docs) - score = tf * idf - pq << FrequencyQueueItem.new(word, top_field, score) - end - pq.compact! - pq.sort! { |a,b| a.score<=>b.score } - return pq - end - - def noise_word?(text, options) - len = text.length - ( - (options[:min_word_length] > 0 && len < options[:min_word_length]) || - (options[:max_word_length] > 0 && len > options[:max_word_length]) || - (options[:stop_words] && options.include?(text)) - ) - end - - end - - class DefaultAAFSimilarity - def idf(doc_freq, num_docs) - return 0.0 if num_docs == 0 - return Math.log(num_docs.to_f/(doc_freq+1)) + 1.0 - end - end - - - class FrequencyQueueItem - attr_reader :word, :field, :score - def initialize(word, field, score) - @word = word; @field = field; @score = score - end - end - - end -end - diff --git a/vendor/plugins/acts_as_ferret/lib/multi_index.rb b/vendor/plugins/acts_as_ferret/lib/multi_index.rb deleted file mode 100644 index 8f9400e..0000000 --- a/vendor/plugins/acts_as_ferret/lib/multi_index.rb +++ /dev/null @@ -1,126 +0,0 @@ -module ActsAsFerret #:nodoc: - - # Base class for remote and local multi-indexes - class MultiIndexBase - include FerretFindMethods - attr_accessor :logger - - def initialize(indexes, options = {}) - # ensure all models indexes exist - @indexes = indexes - indexes.each { |i| i.ensure_index_exists } - default_fields = indexes.inject([]) do |fields, idx| - fields + [ idx.index_definition[:ferret][:default_field] ] - end.flatten.uniq - @options = { - :default_field => default_fields - }.update(options) - @logger = IndexLogger.new(ActsAsFerret::logger, "multi: #{indexes.map(&:index_name).join(',')}") - end - - def ar_find(query, options = {}, ar_options = {}) - limit = options.delete(:limit) - offset = options.delete(:offset) || 0 - options[:limit] = :all - total_hits, result = super query, options, ar_options - total_hits = result.size if ar_options[:conditions] - if limit && limit != :all - result = result[offset..limit+offset-1] - end - [total_hits, result] - end - - def determine_stored_fields(options) - return nil unless options.has_key?(:lazy) - stored_fields = [] - @indexes.each do |index| - stored_fields += index.determine_stored_fields(options) - end - return stored_fields.uniq - end - - def shared? - false - end - - end - - # This class can be used to search multiple physical indexes at once. - class MultiIndex < MultiIndexBase - - def extract_stored_fields(doc, stored_fields) - ActsAsFerret::get_index_for(doc[:class_name]).extract_stored_fields(doc, stored_fields) unless stored_fields.blank? - end - - def total_hits(q, options = {}) - search(q, options).total_hits - end - - def search(query, options={}) - query = process_query(query, options) - logger.debug "parsed query: #{query.to_s}" - searcher.search(query, options) - end - - def search_each(query, options = {}, &block) - query = process_query(query, options) - searcher.search_each(query, options, &block) - end - - # checks if all our sub-searchers still are up to date - def latest? - #return false unless @reader - # segfaults with 0.10.4 --> TODO report as bug @reader.latest? - @reader and @reader.latest? - #@sub_readers.each do |r| - # return false unless r.latest? - #end - #true - end - - def searcher - ensure_searcher - @searcher - end - - def doc(i) - searcher[i] - end - alias :[] :doc - - def query_parser - @query_parser ||= Ferret::QueryParser.new(@options) - end - - def process_query(query, options = {}) - query = query_parser.parse(query) if query.is_a?(String) - return query - end - - def close - @searcher.close if @searcher - @reader.close if @reader - end - - protected - - def ensure_searcher - unless latest? - @sub_readers = @indexes.map { |idx| - begin - reader = Ferret::Index::IndexReader.new(idx.index_definition[:index_dir]) - logger.debug "sub-reader opened: #{reader}" - reader - rescue Exception - raise "error opening reader on index for class #{clazz.inspect}: #{$!}" - end - } - close - @reader = Ferret::Index::IndexReader.new(@sub_readers) - @searcher = Ferret::Search::Searcher.new(@reader) - end - end - - end # of class MultiIndex - -end diff --git a/vendor/plugins/acts_as_ferret/lib/rdig_adapter.rb b/vendor/plugins/acts_as_ferret/lib/rdig_adapter.rb deleted file mode 100644 index d4d3357..0000000 --- a/vendor/plugins/acts_as_ferret/lib/rdig_adapter.rb +++ /dev/null @@ -1,141 +0,0 @@ -begin - require 'rdig' -rescue LoadError -end -module ActsAsFerret - - # The RdigAdapter is automatically included into your model if you specify - # the +:rdig+ options hash in your call to acts_as_ferret. It overrides - # several methods declared by aaf to retrieve documents with the help of - # RDig's http crawler when you call rebuild_index. - module RdigAdapter - - if defined?(RDig) - - def self.included(target) - target.extend ClassMethods - target.send :include, InstanceMethods - end - - # Indexer class to replace RDig's original indexer - class Indexer - include MonitorMixin - def initialize(batch_size, model_class, &block) - @batch_size = batch_size - @model_class = model_class - @documents = [] - @offset = 0 - @block = block - super() - end - - def add(doc) - synchronize do - @documents << @model_class.new(doc.uri.to_s, doc) - process_batch if @documents.size >= @batch_size - end - end - alias << add - - def close - synchronize do - process_batch - end - end - - protected - def process_batch - ActsAsFerret::logger.info "RdigAdapter::Indexer#process_batch: #{@documents.size} docs in queue, offset #{@offset}" - @block.call @documents, @offset - @offset += @documents.size - @documents = [] - end - end - - module ClassMethods - # overriding aaf to return the documents fetched via RDig - def records_for_rebuild(batch_size = 1000, &block) - indexer = Indexer.new(batch_size, self, &block) - configure_rdig do - crawler = RDig::Crawler.new RDig.configuration, ActsAsFerret::logger - crawler.instance_variable_set '@indexer', indexer - ActsAsFerret::logger.debug "now crawling..." - crawler.crawl - end - rescue => e - ActsAsFerret::logger.error e - ActsAsFerret::logger.debug e.backtrace.join("\n") - ensure - indexer.close if indexer - end - - # overriding aaf to skip reindexing records changed during the rebuild - # when rebuilding with the rake task - def records_modified_since(time) - [] - end - - # unfortunately need to modify global RDig.configuration because it's - # used everywhere in RDig - def configure_rdig - # back up original config - old_logger = RDig.logger - old_cfg = RDig.configuration.dup - RDig.logger = ActsAsFerret.logger - rdig_configuration[:crawler].each { |k,v| RDig.configuration.crawler.send :"#{k}=", v } if rdig_configuration[:crawler] - if ce_config = rdig_configuration[:content_extraction] - RDig.configuration.content_extraction = OpenStruct.new( :hpricot => OpenStruct.new( ce_config ) ) - end - yield - ensure - # restore original config - RDig.configuration.crawler = old_cfg.crawler - RDig.configuration.content_extraction = old_cfg.content_extraction - RDig.logger = old_logger - end - - # overriding aaf to enforce loading page title and content from the - # ferret index - def find_with_ferret(q, options = {}, find_options = {}) - options[:lazy] = true - super - end - - def find_for_id(id) - new id - end - end - - module InstanceMethods - def initialize(uri, rdig_document = nil) - @id = uri - @rdig_document = rdig_document - end - - # Title of the document. - # Use the +:title_tag_selector+ option to declare the hpricot expression - # that should be used for selecting the content for this field. - def title - @rdig_document.title - end - - # Content of the document. - # Use the +:content_tag_selector+ option to declare the hpricot expression - # that should be used for selecting the content for this field. - def content - @rdig_document.body - end - - # Url of this document. - def id - @id - end - - def to_s - "Page at #{id}, title: #{title}" - end - end - end - end - -end diff --git a/vendor/plugins/acts_as_ferret/lib/remote_functions.rb b/vendor/plugins/acts_as_ferret/lib/remote_functions.rb deleted file mode 100644 index c92176d..0000000 --- a/vendor/plugins/acts_as_ferret/lib/remote_functions.rb +++ /dev/null @@ -1,23 +0,0 @@ -module ActsAsFerret - module RemoteFunctions - - private - - def yield_results(total_hits, results) - results.each do |result| - yield result[:model], result[:id], result[:score], result[:data] - end - total_hits - end - - - def handle_drb_error(return_value_in_case_of_error = false) - yield - rescue DRb::DRbConnError => e - logger.error "DRb connection error: #{e}" - logger.warn e.backtrace.join("\n") - raise e if ActsAsFerret::raise_drb_errors? - return_value_in_case_of_error - end - end -end diff --git a/vendor/plugins/acts_as_ferret/lib/remote_index.rb b/vendor/plugins/acts_as_ferret/lib/remote_index.rb deleted file mode 100644 index 9c5849e..0000000 --- a/vendor/plugins/acts_as_ferret/lib/remote_index.rb +++ /dev/null @@ -1,54 +0,0 @@ -require 'drb' -module ActsAsFerret - - # This index implementation connects to a remote ferret server instance. It - # basically forwards all calls to the remote server. - class RemoteIndex < AbstractIndex - include RemoteFunctions - - def initialize(config) - super - @server = DRbObject.new(nil, ActsAsFerret::remote) - end - - # Cause model classes to be loaded (and indexes get declared) on the DRb - # side of things. - def register_class(clazz, options) - handle_drb_error { @server.register_class clazz.name } - end - - def method_missing(method_name, *args) - args.unshift index_name - handle_drb_error { @server.send(method_name, *args) } - end - - # Proxy any methods that require special return values in case of errors - { - :highlight => [] - }.each do |method_name, default_result| - define_method method_name do |*args| - args.unshift index_name - handle_drb_error(default_result) { @server.send method_name, *args } - end - end - - def find_ids(q, options = {}, &proc) - total_hits, results = handle_drb_error([0, []]) { @server.find_ids(index_name, q, options) } - block_given? ? yield_results(total_hits, results, &proc) : [ total_hits, results ] - end - - # add record to index - def add(record) - handle_drb_error { @server.add index_name, record.to_doc } - end - alias << add - - private - - #def model_class_name - # index_definition[:class_name] - #end - - end - -end diff --git a/vendor/plugins/acts_as_ferret/lib/remote_multi_index.rb b/vendor/plugins/acts_as_ferret/lib/remote_multi_index.rb deleted file mode 100644 index 7affd43..0000000 --- a/vendor/plugins/acts_as_ferret/lib/remote_multi_index.rb +++ /dev/null @@ -1,20 +0,0 @@ -module ActsAsFerret - class RemoteMultiIndex < MultiIndexBase - include RemoteFunctions - - def initialize(indexes, options = {}) - @index_names = indexes.map(&:index_name) - @server = DRbObject.new(nil, ActsAsFerret::remote) - super - end - - def find_ids(query, options, &proc) - total_hits, results = handle_drb_error([0, []]) { @server.multi_find_ids(@index_names, query, options) } - block_given? ? yield_results(total_hits, results, &proc) : [ total_hits, results ] - end - - def method_missing(name, *args) - handle_drb_error { @server.send(:"multi_#{name}", @index_names, *args) } - end - end -end diff --git a/vendor/plugins/acts_as_ferret/lib/search_results.rb b/vendor/plugins/acts_as_ferret/lib/search_results.rb deleted file mode 100644 index e3da6a2..0000000 --- a/vendor/plugins/acts_as_ferret/lib/search_results.rb +++ /dev/null @@ -1,50 +0,0 @@ -module ActsAsFerret - - # decorator that adds a total_hits accessor and will_paginate compatible - # paging support to search result arrays - class SearchResults < ActsAsFerret::BlankSlate - reveal :methods - attr_reader :current_page, :per_page, :total_hits, :total_pages - alias total_entries total_hits # will_paginate compatibility - alias page_count total_pages # will_paginate backwards compatibility - - def initialize(results, total_hits, current_page = 1, per_page = nil) - @results = results - @total_hits = total_hits - @current_page = current_page - @per_page = (per_page || total_hits) - @total_pages = @per_page > 0 ? (@total_hits / @per_page.to_f).ceil : 0 - end - - def method_missing(symbol, *args, &block) - @results.send(symbol, *args, &block) - end - - def respond_to?(name) - methods.include?(name.to_s) || @results.respond_to?(name) - end - - - # code from here on was directly taken from will_paginate's collection.rb - - # Current offset of the paginated collection. If we're on the first page, - # it is always 0. If we're on the 2nd page and there are 30 entries per page, - # the offset is 30. This property is useful if you want to render ordinals - # besides your records: simply start with offset + 1. - # - def offset - (current_page - 1) * per_page - end - - # current_page - 1 or nil if there is no previous page - def previous_page - current_page > 1 ? (current_page - 1) : nil - end - - # current_page + 1 or nil if there is no next page - def next_page - current_page < total_pages ? (current_page + 1) : nil - end - end - -end diff --git a/vendor/plugins/acts_as_ferret/lib/server_manager.rb b/vendor/plugins/acts_as_ferret/lib/server_manager.rb deleted file mode 100644 index a5a1687..0000000 --- a/vendor/plugins/acts_as_ferret/lib/server_manager.rb +++ /dev/null @@ -1,58 +0,0 @@ -################################################################################ -require 'optparse' - -################################################################################ -$ferret_server_options = { - 'environment' => nil, - 'debug' => nil, - 'root' => nil -} - -################################################################################ -OptionParser.new do |optparser| - optparser.banner = "Usage: #{File.basename($0)} [options] {start|stop|run}" - - optparser.on('-h', '--help', "This message") do - puts optparser - exit - end - - optparser.on('-R', '--root=PATH', 'Set RAILS_ROOT to the given string') do |r| - $ferret_server_options['root'] = r - end - - optparser.on('-e', '--environment=NAME', 'Set RAILS_ENV to the given string') do |e| - $ferret_server_options['environment'] = e - end - - optparser.on('--debug', 'Include full stack traces on exceptions') do - $ferret_server_options['debug'] = true - end - - $ferret_server_action = optparser.permute!(ARGV) - (puts optparser; exit(1)) unless $ferret_server_action.size == 1 - - $ferret_server_action = $ferret_server_action.first - (puts optparser; exit(1)) unless %w(start stop run).include?($ferret_server_action) -end - -################################################################################ -begin - ENV['FERRET_USE_LOCAL_INDEX'] = 'true' - ENV['RAILS_ENV'] = $ferret_server_options['environment'] - - # determine RAILS_ROOT unless already set - RAILS_ROOT = $ferret_server_options['root'] || File.join(File.dirname(__FILE__), *(['..']*4)) unless defined? RAILS_ROOT - # check if environment.rb is present - rails_env_file = File.join(RAILS_ROOT, 'config', 'environment') - raise "Unable to find Rails environment.rb at \n#{rails_env_file}.rb\nPlease use the --root option of ferret_server to point it to your RAILS_ROOT." unless File.exists?(rails_env_file+'.rb') - # load it - require rails_env_file - - require 'acts_as_ferret' - ActsAsFerret::Remote::Server.new.send($ferret_server_action) -rescue Exception => e - $stderr.puts(e.message) - $stderr.puts(e.backtrace.join("\n")) if $ferret_server_options['debug'] - exit(1) -end diff --git a/vendor/plugins/acts_as_ferret/lib/unix_daemon.rb b/vendor/plugins/acts_as_ferret/lib/unix_daemon.rb deleted file mode 100644 index ceaf2d7..0000000 --- a/vendor/plugins/acts_as_ferret/lib/unix_daemon.rb +++ /dev/null @@ -1,64 +0,0 @@ -################################################################################ -module ActsAsFerret - module Remote - - ################################################################################ - # methods for becoming a daemon on Unix-like operating systems - module UnixDaemon - - ################################################################################ - def platform_daemon (&block) - safefork do - write_pid_file - trap("TERM") { exit(0) } - sess_id = Process.setsid - STDIN.reopen("/dev/null") - STDOUT.reopen("#{RAILS_ROOT}/log/ferret_server.out", "a") - STDERR.reopen(STDOUT) - block.call - end - end - - ################################################################################ - # stop the daemon, nicely at first, and then forcefully if necessary - def stop - pid = read_pid_file - raise "ferret_server doesn't appear to be running" unless pid - $stdout.puts("stopping ferret server...") - Process.kill("TERM", pid) - 30.times { Process.kill(0, pid); sleep(0.5) } - $stdout.puts("using kill -9 #{pid}") - Process.kill(9, pid) - rescue Errno::ESRCH => e - $stdout.puts("process #{pid} has stopped") - ensure - File.unlink(@cfg.pid_file) if File.exist?(@cfg.pid_file) - end - - ################################################################################ - def safefork (&block) - @fork_tries ||= 0 - fork(&block) - rescue Errno::EWOULDBLOCK - raise if @fork_tries >= 20 - @fork_tries += 1 - sleep 5 - retry - end - - ################################################################################# - # create the PID file and install an at_exit handler - def write_pid_file - raise "ferret_server may already be running, a pid file exists: #{@cfg.pid_file}" if read_pid_file - open(@cfg.pid_file, "w") {|f| f << Process.pid << "\n"} - at_exit { File.unlink(@cfg.pid_file) if read_pid_file == Process.pid } - end - - ################################################################################# - def read_pid_file - File.read(@cfg.pid_file).to_i if File.exist?(@cfg.pid_file) - end - - end - end -end diff --git a/vendor/plugins/acts_as_ferret/lib/without_ar.rb b/vendor/plugins/acts_as_ferret/lib/without_ar.rb deleted file mode 100644 index f6afde0..0000000 --- a/vendor/plugins/acts_as_ferret/lib/without_ar.rb +++ /dev/null @@ -1,49 +0,0 @@ -module ActsAsFerret - - # Include this module to use acts_as_ferret with model classes - # not based on ActiveRecord. - # - # Implement the find_for_id(id) class method in your model class in - # order to make search work. - module WithoutAR - def self.included(target) - target.extend ClassMethods - target.extend ActsAsFerret::ActMethods - target.send :include, InstanceMethods - end - - module ClassMethods - def logger - RAILS_DEFAULT_LOGGER - end - def table_name - self.name.underscore - end - def primary_key - 'id' - end - def find(what, args = {}) - case what - when :all - ids = args[:conditions][1] - ids.map { |id| find id } - else - find_for_id what - end - end - def find_for_id(id) - raise NotImplementedError.new("implement find_for_id in class #{self.name}") - end - def count - 0 - end - end - - module InstanceMethods - def logger - self.class.logger - end - end - end - -end diff --git a/vendor/plugins/acts_as_ferret/rakefile b/vendor/plugins/acts_as_ferret/rakefile deleted file mode 100644 index 65ef39a..0000000 --- a/vendor/plugins/acts_as_ferret/rakefile +++ /dev/null @@ -1,134 +0,0 @@ -# rakefile for acts_as_ferret. -# use to create a gem or generate rdoc api documentation. -# -# RELEASE creation: -# rake release REL=x.y.z - -require 'rake' -require 'rake/rdoctask' -require 'rake/packagetask' -require 'rake/gempackagetask' -require 'rake/testtask' -require 'rake/contrib/rubyforgepublisher' - -def announce(msg='') - STDERR.puts msg -end - - -PKG_NAME = 'acts_as_ferret' -PKG_VERSION = ENV['REL'] -PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}" -RUBYFORGE_PROJECT = 'actsasferret' -RUBYFORGE_USER = 'jkraemer' - -desc 'Default: run unit tests.' -task :default => :test - -desc 'Test the acts_as_ferret plugin.' -Rake::TestTask.new(:test) do |t| - t.libs << 'lib' - t.pattern = 'test/**/*_test.rb' - t.verbose = true -end - -desc 'Generate documentation for the acts_as_ferret plugin.' -Rake::RDocTask.new(:rdoc) do |rdoc| - rdoc.rdoc_dir = 'html' - rdoc.title = "acts_as_ferret - Ferret based full text search for any ActiveRecord model" - rdoc.options << '--line-numbers' << '--inline-source' - rdoc.options << '--main' << 'README' - rdoc.rdoc_files.include('README', 'LICENSE') - rdoc.template = "#{ENV['template']}.rb" if ENV['template'] - rdoc.rdoc_files.include('lib/**/*.rb') -end - -desc "Publish the API documentation" -task :pdoc => [:rdoc] do - Rake::RubyForgePublisher.new(RUBYFORGE_PROJECT, RUBYFORGE_USER).upload -end - -if PKG_VERSION - spec = Gem::Specification.new do |s| - s.name = PKG_NAME - s.version = PKG_VERSION - s.platform = Gem::Platform::RUBY - s.summary = "acts_as_ferret - Ferret based full text search for any ActiveRecord model" - s.files = Dir.glob('**/*', File::FNM_DOTMATCH).reject do |f| - [ /\.$/, /sqlite$/, /\.log$/, /^pkg/, /\.svn/, /\.\w+\.sw.$/, - /^html/, /\~$/, /\/\._/, /\/#/ ].any? {|regex| f =~ regex } - end - #s.files = FileList["{lib,test}/**/*"].to_a + %w(README MIT-LICENSE CHANGELOG) - # s.files.delete ... - s.require_path = 'lib' - s.bindir = "bin" - s.executables = ["aaf_install"] - s.default_executable = "aaf_install" - s.autorequire = 'acts_as_ferret' - s.has_rdoc = true - # s.test_files = Dir['test/**/*_test.rb'] - s.author = "Jens Kraemer" - s.email = "jk@jkraemer.net" - s.homepage = "http://projects.jkraemer.net/acts_as_ferret" - end - - package_task = Rake::GemPackageTask.new(spec) do |pkg| - pkg.need_tar = true - end - - # Validate that everything is ready to go for a release. - task :prerelease do - announce - announce "**************************************************************" - announce "* Making RubyGem Release #{PKG_VERSION}" - announce "**************************************************************" - announce - # Are all source files checked in? - if ENV['RELTEST'] - announce "Release Task Testing, skipping checked-in file test" - else - announce "Pulling in svn..." - `svk pull .` - announce "Checking for unchecked-in files..." - data = `svk st` - unless data =~ /^$/ - fail "SVK status is not clean ... do you have unchecked-in files?" - end - announce "No outstanding checkins found ... OK" -# announce "Pushing to svn..." -# `svk push .` - end - end - - - desc "tag the new release" - task :tag => [ :prerelease ] do - reltag = "REL_#{PKG_VERSION.gsub(/\./, '_')}" - reltag << ENV['REUSE'].gsub(/\./, '_') if ENV['REUSE'] - announce "Tagging with [#{PKG_VERSION}]" - if ENV['RELTEST'] - announce "Release Task Testing, skipping tagging" - else - `svn copy -m 'tagging version #{PKG_VERSION}' svn://projects.jkraemer.net/acts_as_ferret/trunk/plugin svn://projects.jkraemer.net/acts_as_ferret/tags/#{PKG_VERSION}` - `svn del -m 'remove old stable' svn://projects.jkraemer.net/acts_as_ferret/tags/stable` - `svn copy -m 'tagging version #{PKG_VERSION} as stable' svn://projects.jkraemer.net/acts_as_ferret/tags/#{PKG_VERSION} svn://projects.jkraemer.net/acts_as_ferret/tags/stable` - end - end - - # Upload release to rubyforge - desc "Upload release to rubyforge" - task :prel => [ :tag, :prerelease, :package ] do - `rubyforge login` - release_command = "rubyforge add_release #{RUBYFORGE_PROJECT} #{PKG_NAME} '#{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.gem" - puts release_command - system(release_command) - `rubyforge config #{RUBYFORGE_PROJECT}` - release_command = "rubyforge add_file #{RUBYFORGE_PROJECT} #{PKG_NAME} '#{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.tgz" - puts release_command - system(release_command) - end - - desc 'Publish the gem and API docs' - task :release => [:pdoc, :prel ] - -end diff --git a/vendor/plugins/acts_as_ferret/recipes/aaf_recipes.rb b/vendor/plugins/acts_as_ferret/recipes/aaf_recipes.rb deleted file mode 100644 index d8203e6..0000000 --- a/vendor/plugins/acts_as_ferret/recipes/aaf_recipes.rb +++ /dev/null @@ -1,97 +0,0 @@ -# Ferret DRb server Capistrano tasks -# -# Usage: -# in your Capfile, add acts_as_ferret's recipes directory to your load path and -# load the ferret tasks: -# -# load_paths << 'vendor/plugins/acts_as_ferret/recipes' -# load 'aaf_recipes' -# -# This will hook aaf's DRb start/stop tasks into the standard -# deploy:{start|restart|stop} tasks so the server will be restarted along with -# the rest of your application. -# Also an index directory in the shared folder will be created and symlinked -# into current/ when you deploy. -# -# In order to use the ferret:index:rebuild task, declare the indexes you intend to -# rebuild remotely in config/deploy.rb: -# -# set :ferret_indexes, %w( model another_model shared ) -# -# HINT: To be very sure that your DRb server and application are always using -# the same model and schema versions, and you never lose any index updates because -# of the DRb server being restarted in that moment, use the following sequence -# to update your application: -# -# cap deploy:stop deploy:update deploy:migrate deploy:start -# -# That will stop the DRb server after stopping your application, and bring it -# up before starting the application again. Plus they'll never use different -# versions of model classes (which might happen otherwise) -# Downside: Your downtime is a bit longer than with the usual deploy, so be sure to -# put up some maintenance page for the meantime. Obviously this won't work if -# your migrations need acts_as_ferret (i.e. if you update model instances which -# would lead to index updates). In this case bring up the DRb server before -# running your migrations: -# -# cap deploy:stop deploy:update ferret:start deploy:migrate ferret:stop deploy:start -# -# Chances are that you're still not safe if your migrations not only modify the index, -# but also change the structure of your models. So just don't do both things in -# one go - I can't think of an easy way to handle this case automatically. -# Suggestions and patches are of course very welcome :-) - -namespace :ferret do - - desc "Stop the Ferret DRb server" - task :stop, :roles => :app do - rails_env = fetch(:rails_env, 'production') - run "cd #{current_path}; script/ferret_server -e #{rails_env} stop || true" - end - - desc "Start the Ferret DRb server" - task :start, :roles => :app do - rails_env = fetch(:rails_env, 'production') - run "cd #{current_path}; script/ferret_server -e #{rails_env} start" - end - - desc "Restart the Ferret DRb server" - task :restart, :roles => :app do - top.ferret.stop - sleep 1 - top.ferret.start - end - - namespace :index do - - desc "Rebuild the Ferret index. See aaf_recipes.rb for instructions." - task :rebuild => :environment, :roles => :app do - rake = fetch(:rake, 'rake') - rails_env = fetch(:rails_env, 'production') - indexes = fetch(:ferret_indexes, nil) - if indexes and indexes.any? - run "cd #{current_path}; RAILS_ENV=#{rails_env} INDEXES='#{indexes.join(' ')}' #{rake} ferret:rebuild" - end - end - - desc "purges all indexes for the current environment" - task :purge, :roles => :app do - run "rm -fr #{shared_path}/index/#{rails_env}" - end - - desc "symlinks index folder" - task :symlink, :roles => :app do - run "mkdir -p #{shared_path}/index && rm -rf #{release_path}/index && ln -nfs #{shared_path}/index #{release_path}/index" - end - - end - -end - -after "deploy:stop", "ferret:stop" -before "deploy:start", "ferret:start" - -before "deploy:restart", "ferret:stop" -after "deploy:restart", "ferret:start" -after "deploy:symlink", "ferret:index:symlink" - diff --git a/vendor/plugins/acts_as_ferret/script/ferret_daemon b/vendor/plugins/acts_as_ferret/script/ferret_daemon deleted file mode 100644 index 631c4b5..0000000 --- a/vendor/plugins/acts_as_ferret/script/ferret_daemon +++ /dev/null @@ -1,94 +0,0 @@ -# Ferret Win32 Service Daemon, called by Win 32 service, -# created by Herryanto Siatono -# -# see doc/README.win32 for usage instructions -# -require 'optparse' -require 'win32/service' -include Win32 - -# Read options -options = {} -ARGV.options do |opts| - opts.banner = 'Usage: ferret_daemon [options]' - opts.on("-l", "--log FILE", "Daemon log file") {|file| options[:log] = file } - opts.on("-c","--console","Run Ferret server on console.") {options[:console] = true} - opts.on_tail("-h","--help", "Show this help message") {puts opts; exit} - opts.on("-e", "--environment ENV ", "Rails environment") {|env| - options[:environment] = env - ENV['RAILS_ENV'] = env - } - opts.parse! -end - -require File.dirname(__FILE__) + '/../config/environment' - -# Ferret Win32 Service Daemon, called by Win 32 service, -# to run on the console, use -c or --console option. -module Ferret - class FerretDaemon < Daemon - # Standard logger to redirect STDOUT and STDERR to a log file - class FerretStandardLogger - def initialize(logger) - @logger = logger - end - - def write(s) - @logger.info s - end - end - - def initialize(options={}) - @options = options - - # initialize logger - if options[:log] - @logger = Logger.new @options[:log] - else - @logger = Logger.new RAILS_ROOT + "/log/ferret_service_#{RAILS_ENV}.log" - end - - # redirect stout and stderr to Ferret logger if running as windows service - $stdout = $stderr = FerretStandardLogger.new(@logger) unless @options[:console] - - log "Initializing FerretDaemon..." - if @options[:console] - self.service_init - self.service_main - end - end - - def service_main - log "Service main enterred..." - - while running? - log "Listening..." - sleep - end - - log "Service main exit..." - end - - def service_init - log "Starting Ferret DRb server..." - ActsAsFerret::Remote::Server.start - log "FerretDaemon started." - end - - def service_stop - log "Stopping service..." - DRb.stop_service - log "FerretDaemon stopped." - end - - def log(msg) - @logger.info msg - puts msg if @options[:console] - end - end -end - -if __FILE__ == $0 - d = Ferret::FerretDaemon.new(options) - d.mainloop -end diff --git a/vendor/plugins/acts_as_ferret/script/ferret_server b/vendor/plugins/acts_as_ferret/script/ferret_server deleted file mode 100644 index f5dbf3a..0000000 --- a/vendor/plugins/acts_as_ferret/script/ferret_server +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env ruby - -begin - require File.join(File.dirname(__FILE__), '../vendor/plugins/acts_as_ferret/lib/server_manager') -rescue LoadError - # try the gem - require 'rubygems' - gem 'acts_as_ferret' - require 'server_manager' -end diff --git a/vendor/plugins/acts_as_ferret/script/ferret_service b/vendor/plugins/acts_as_ferret/script/ferret_service deleted file mode 100644 index 6c56443..0000000 --- a/vendor/plugins/acts_as_ferret/script/ferret_service +++ /dev/null @@ -1,178 +0,0 @@ -# Ferret Win32 Service Daemon install script -# created by Herryanto Siatono -# -# see doc/README.win32 for usage instructions -# -require 'optparse' -require 'win32/service' -include Win32 - -module Ferret - # Parse and validate service command and options - class FerretServiceCommand - COMMANDS = ['install', 'remove', 'start', 'stop', 'help'] - BANNER = "Usage: ruby script/ferret_service [options]" - - attr_reader :options, :command - - def initialize - @options = {} - end - - def valid_command? - COMMANDS.include?@command - end - - def valid_options? - @options[:name] and !@options[:name].empty? - end - - def print_command_list - puts BANNER - puts "\nAvailable commands:\n" - puts COMMANDS.map {|cmd| " - #{cmd}\n"} - puts "\nUse option -h for each command to help." - exit - end - - def validate_options - errors = [] - errors << "Service name is required." unless @options[:name] - - if (errors.size > 0) - errors << "Error found. Use: 'ruby script/ferret_service #{@command} -h' for to get help." - puts errors.join("\n") - exit - end - end - - def run(args) - @command = args.shift - @command = @command.dup.downcase if @command - - # validate command and options - print_command_list unless valid_command? or @command == 'help' - - opts_parser = create_options_parser - begin - opts_parser.parse!(args) - rescue OptionParser::ParseError => e - puts e - puts opts_parser - end - - # validate required options - validate_options - end - - def create_options_parser - opts_parser = OptionParser.new - opts_parser.banner = BANNER - opts_parser.on("-n", "--name=NAME", "Service name") {|name| @options[:name] = name } - opts_parser.on_tail("-t", "--trace", "Display stack trace when exception thrown") { @options[:trace] = true } - opts_parser.on_tail("-h", "--help", "Show this help message") { puts opts_parser; exit } - - if ['install'].include?@command - opts_parser.on("-d", "--display=NAME", "Service display name") {|name| @options[:display] = name } - - opts_parser.on("-l", "--log FILE", "Service log file") {|file| @options[:log] = file } - opts_parser.on("-e", "--environment ENV ", "Rails environment") { |env| - @options[:environment] = env - ENV['RAILS_ENV'] = env - } - end - opts_parser - end - end - - # Install, Remove, Start and Stop Ferret DRb server Win32 service - class FerretService - FERRET_DAEMON = 'ferret_daemon' - - def initialize - end - - def install - svc = Service.new - - begin - if Service.exists?(@options[:name]) - puts "Service name '#{@options[:name]}' already exists." - return - end - - svc.create_service do |s| - s.service_name = @options[:name] - s.display_name = @options[:display] - s.binary_path_name = binary_path_name - s.dependencies = [] - end - - svc.close - puts "'#{@options[:name]}' service installed." - rescue => e - handle_error(e) - end - end - - def remove - begin - Service.stop(@options[:name]) - rescue - end - - begin - Service.delete(@options[:name]) - puts "'#{@options[:name]}' service removed." - rescue => e - handle_error(e) - end - end - - def start - begin - Service.start(@options[:name]) - puts "'#{@options[:name]}' successfully started." - rescue => e - handle_error(e) - end - end - - def stop - begin - Service.stop(@options[:name]) - puts "'#{@options[:name]}' successfully stopped.\n" - rescue => e - handle_error(e) - end - end - - def run(args) - svc_cmd = FerretServiceCommand.new - svc_cmd.run(args) - @options = svc_cmd.options - self.send(svc_cmd.command.to_sym) - end - - protected - def handle_error(e) - if @options[:trace] - raise e - else - puts e - end - end - - def binary_path_name - path = "" - path << "#{ENV['RUBY_HOME']}/bin/" if ENV['RUBY_HOME'] - path << "ruby.exe " - path << File.expand_path("script/" + FERRET_DAEMON) - path << " -e #{@options[:environment]} " if @options[:environment] - path << " -l #{@options[:log]} " if @options[:log] - path - end - end -end - -Ferret::FerretService.new.run(ARGV) diff --git a/vendor/plugins/acts_as_ferret/tasks/ferret.rake b/vendor/plugins/acts_as_ferret/tasks/ferret.rake deleted file mode 100644 index 7a761aa..0000000 --- a/vendor/plugins/acts_as_ferret/tasks/ferret.rake +++ /dev/null @@ -1,24 +0,0 @@ -namespace :ferret do - - # Rebuild index task. Declare the indexes to be rebuilt with the INDEXES - # environment variable: - # - # INDEXES="my_model shared" rake ferret:rebuild - desc "Rebuild a Ferret index. Specify what model to rebuild with the MODEL environment variable." - task :rebuild do - require File.join(RAILS_ROOT, 'config', 'environment') - - indexes = ENV['INDEXES'].split - indexes.each do |index_name| - start = 1.minute.ago - ActsAsFerret::rebuild_index index_name - idx = ActsAsFerret::get_index index_name - # update records that have changed since the rebuild started - idx.index_definition[:registered_models].each do |m| - m.records_modified_since(start).each do |object| - object.ferret_update - end - end - end - end -end diff --git a/vendor/plugins/acts_as_solr_reloaded/.gitignore b/vendor/plugins/acts_as_solr_reloaded/.gitignore new file mode 100644 index 0000000..c855325 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/.gitignore @@ -0,0 +1,17 @@ +*.log +*.log +*_pid +coverage/* +coverage.data +solr/solr/data/* +.svn +test/db/*.db +test/log/*.log +pkg/* +*.sw? +.DS_Store +coverage +rdoc +pkg +acts_as_solr_reloaded-*.gem +tags diff --git a/vendor/plugins/acts_as_solr_reloaded/LICENSE b/vendor/plugins/acts_as_solr_reloaded/LICENSE new file mode 100644 index 0000000..4b2cf05 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright © 2010 + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +‘Software’), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/plugins/acts_as_solr_reloaded/README.markdown b/vendor/plugins/acts_as_solr_reloaded/README.markdown new file mode 100644 index 0000000..9d2f240 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/README.markdown @@ -0,0 +1,64 @@ +Description +====== +This plugin adds full text search capabilities and many other nifty features from Apache's [Solr](http://lucene.apache.org/solr/) to any Rails model. +It was based on the first draft by Erik Hatcher. + +This plugin is intended for use in old versions of Rails. For newer versions, I strongly advice using Sunspot! +Nevertheless, this plugin is used for Noosfero project in production. Any problem please open an issue. + +Installation +====== + +Install as a plugin + + script/plugin install git://github.com/brauliobo/acts_as_solr_reloaded.git + +Download Solr 3.1 + + rake solr:download + +Requirements +------ +* Java Runtime Environment(JRE) 1.6 aka 6.0 or newer [http://www.java.com/en/download/index.jsp](http://www.java.com/en/download/index.jsp) (use default-jre for Debian like distribution) +* (Recommended) If you have libxml-ruby installed, make sure it's at least version 0.7 + +Configuration +====== +See config/solr.yml file. + +Basic Usage +====== +

+# Just include the line below to any of your ActiveRecord models:
+  acts_as_solr
+
+# Or if you want, you can specify only the fields that should be indexed:
+  acts_as_solr :fields => [:name, :author]
+
+# Then to find instances of your model, just do:
+  Model.search(query) #query is a string representing your query
+
+# Please see ActsAsSolr::ActsMethods for a complete info
+
+
+ + +`acts_as_solr` in your tests +====== +To test code that uses `acts_as_solr` you must start a Solr server for the test environment. You can do that with `rake solr:start RAILS_ENV=test` + +However, if you would like to mock out Solr calls so that a Solr server is not needed (and your tests will run much faster), just add this to your `test_helper.rb` or similar: + +

+class ActsAsSolr::Post
+  def self.execute(request)
+    true
+  end
+end
+
+ +([via](http://www.subelsky.com/2007/10/actsassolr-capistranhttpwwwbloggercomim.html#c1646308013209805416)) + +Release Information +====== +Released under the MIT license. diff --git a/vendor/plugins/acts_as_solr_reloaded/README.rdoc b/vendor/plugins/acts_as_solr_reloaded/README.rdoc new file mode 100644 index 0000000..08d77e0 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/README.rdoc @@ -0,0 +1,96 @@ += DESCRIPTION + +This plugin adds full text search capabilities and many other nifty features from Apache's Solr[http://lucene.apache.org/solr/] to any Rails model, like: + +* faceting +* dynamic attributes +* integration with acts_as_taggable_on +* integration with will_paginate +* highlighting +* geolocation +* relevance +* suggest + +Watch this screencast for a short demo of the latests features: + +http://www.vimeo.com/8728276 + +== INSTALLATION + + script/plugin install git://github.com/brauliobo/acts_as_solr_reloaded.git + rake solr:download + +== REQUIREMENTS + +* Java Runtime Environment(JRE) 1.5 aka 5.0 [http://www.java.com/en/download/index.jsp](http://www.java.com/en/download/index.jsp) (use default-jre for Debian like distribution) +* (Recommended) If you have libxml-ruby installed, make sure it's at least version 0.7 + +== CONFIGURATION + +See config/solr.yml file. + +== USAGE + +Just include the line below to any of your ActiveRecord models: + acts_as_solr + +Or if you want, you can specify only the fields that should be indexed: + acts_as_solr :fields => [:name, :author] + +Then to find instances of your model, just do: + Model.search(query) #query is a string representing your query + +Case you want to use dynamic attributes or geolocalization, you can use this generators that setup the database: + + script/generate dynamic_attributes_migration + script/generate local_migration + +and then configure your model like this: + + acts_as_solr :dynamic_attributes => true, + :spatial => true + +If you want to integrate the model with acts_as_taggable_on, just add the option :taggable => true : + + acts_as_solr :taggable => true + +Please see ActsAsSolr::ActsMethods for a complete info + +== PAGINATION + +In your controller: + + @search = Product.search "beer", :page => 2, :per_page => 20 + +And in your view: + + will_paginate @search + +== TESTING + +To test code that uses acts_as_solr_reloaded you must start a Solr server for the test environment and also start MongoDB. + +== LICENSE + +(The MIT License) + +Copyright © 2010 + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +‘Software’), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/plugins/acts_as_solr_reloaded/Rakefile b/vendor/plugins/acts_as_solr_reloaded/Rakefile new file mode 100644 index 0000000..18b5a86 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/Rakefile @@ -0,0 +1,71 @@ +require 'rubygems' +require 'rake' +require 'rake/testtask' +require 'rake/rdoctask' + +Dir["#{File.dirname(__FILE__)}/lib/tasks/*.rake"].sort.each { |ext| load ext } + +desc "Default Task" +task :default => [:test] + +desc "Runs the unit tests" +task :test => "test:unit" + +namespace :test do + task :setup do + RAILS_ROOT = File.expand_path("#{File.dirname(__FILE__)}/test") unless defined? RAILS_ROOT + ENV['RAILS_ENV'] = "test" + ENV["ACTS_AS_SOLR_TEST"] = "true" + require File.expand_path("#{File.dirname(__FILE__)}/config/solr_environment") + puts "Using " + DB + %x(mysql -u#{MYSQL_USER} < #{File.dirname(__FILE__) + "/test/fixtures/db_definitions/mysql.sql"}) if DB == 'mysql' + + Rake::Task["test:migrate"].invoke + end + + desc 'Measures test coverage using rcov' + task :rcov => :setup do + rm_f "coverage" + rm_f "coverage.data" + rcov = "rcov --rails --aggregate coverage.data --text-summary -Ilib" + + system("#{rcov} --html #{Dir.glob('test/**/*_shoulda.rb').join(' ')}") + system("open coverage/index.html") if PLATFORM['darwin'] + end + + desc 'Runs the functional tests, testing integration with Solr' + Rake::TestTask.new('functional' => :setup) do |t| + t.pattern = "test/functional/*_test.rb" + t.verbose = true + end + + desc "Unit tests" + Rake::TestTask.new(:unit) do |t| + t.libs << 'test/unit' + t.pattern = "test/unit/*_shoulda.rb" + t.verbose = true + end +end + +Rake::RDocTask.new do |rd| + rd.main = "README.rdoc" + rd.rdoc_dir = "rdoc" + rd.rdoc_files.exclude("lib/solr/**/*.rb", "lib/solr.rb") + rd.rdoc_files.include("README.rdoc", "lib/**/*.rb") +end + +begin + require 'jeweler' + Jeweler::Tasks.new do |s| + s.name = "acts_as_solr_reloaded" + s.summary = "This gem adds full text search capabilities and many other nifty features from Apache Solr to any Rails model." + s.email = "dc.rec1@gmail.com" + s.homepage = "http://github.com/dcrec1/acts_as_solr_reloaded" + s.description = "This gem adds full text search capabilities and many other nifty features from Apache Solr to any Rails model." + s.authors = ["Diego Carrion"] + s.files = FileList["[A-Z]*", "{bin,generators,config,lib,solr}/**/*"] + + FileList["test/**/*"].reject {|f| f.include?("test/log")}.reject {|f| f.include?("test/tmp")} + end +rescue LoadError + puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install jeweler" +end diff --git a/vendor/plugins/acts_as_solr_reloaded/TESTING_THE_PLUGIN b/vendor/plugins/acts_as_solr_reloaded/TESTING_THE_PLUGIN new file mode 100644 index 0000000..2404a55 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/TESTING_THE_PLUGIN @@ -0,0 +1,25 @@ +acts_as_solr comes with a quick and fast unit test suite, and with a longer-running +functional test suite, the latter testing the actual integration with Solr. + +The unit test suite is written using Shoulda, so make sure you have a recent version +installed. + +Running `rake test` or just `rake` will run both test suites. Use `rake test:unit` to +just run the unit test suite. + +== How to run functional tests for this plugin: +To run the acts_as_solr's plugin tests run the following steps: + +- create a MySQL database called "actsassolr_test" (if you want to use MySQL) + +- create a new Rails project, if needed (the plugin can only be tested from within a Rails project); move/checkout acts_as_solr into its vendor/plugins/, as usual + +- copy vendor/plugins/acts_as_solr_reloaded/config/solr.yml to config/ (the Rails config folder) + +- rake solr:start RAILS_ENV=test + +- rake test:functional (Accepts the following arguments: DB=sqlite|mysql and MYSQL_USER=user) + +== Troubleshooting: +If for some reason the tests don't run and you get MySQL errors, make sure you edit the MYSQL_USER entry under +config/environment.rb. It's recommended to create or use a MySQL user with no password. diff --git a/vendor/plugins/acts_as_solr_reloaded/VERSION b/vendor/plugins/acts_as_solr_reloaded/VERSION new file mode 100644 index 0000000..ce6a70b --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/VERSION @@ -0,0 +1 @@ +1.6.0 \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/acts_as_solr_reloaded.gemspec b/vendor/plugins/acts_as_solr_reloaded/acts_as_solr_reloaded.gemspec new file mode 100644 index 0000000..45afb41 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/acts_as_solr_reloaded.gemspec @@ -0,0 +1,205 @@ +# Generated by jeweler +# DO NOT EDIT THIS FILE DIRECTLY +# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec' +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = %q{acts_as_solr_reloaded} + s.version = "1.6.0" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["Diego Carrion"] + s.date = %q{2011-03-20} + s.description = %q{This gem adds full text search capabilities and many other nifty features from Apache Solr to any Rails model.} + s.email = %q{dc.rec1@gmail.com} + s.extra_rdoc_files = [ + "LICENSE", + "README.markdown", + "README.rdoc" + ] + s.files = [ + "LICENSE", + "README.markdown", + "README.rdoc", + "Rakefile", + "TESTING_THE_PLUGIN", + "VERSION", + "config/solr.yml", + "config/solr_environment.rb", + "generators/dynamic_attributes_migration/dynamic_attributes_migration_generator.rb", + "generators/dynamic_attributes_migration/templates/migration.rb", + "generators/local_migration/local_migration_generator.rb", + "generators/local_migration/templates/migration.rb", + "lib/acts_as_solr.rb", + "lib/acts_as_solr/acts_methods.rb", + "lib/acts_as_solr/class_methods.rb", + "lib/acts_as_solr/common_methods.rb", + "lib/acts_as_solr/deprecation.rb", + "lib/acts_as_solr/dynamic_attribute.rb", + "lib/acts_as_solr/instance_methods.rb", + "lib/acts_as_solr/lazy_document.rb", + "lib/acts_as_solr/local.rb", + "lib/acts_as_solr/mongo_mapper.rb", + "lib/acts_as_solr/parser_methods.rb", + "lib/acts_as_solr/search_results.rb", + "lib/acts_as_solr/solr_fixtures.rb", + "lib/acts_as_solr/tasks.rb", + "lib/acts_as_solr_reloaded.rb", + "lib/solr.rb", + "lib/solr/connection.rb", + "lib/solr/document.rb", + "lib/solr/exception.rb", + "lib/solr/field.rb", + "lib/solr/importer.rb", + "lib/solr/importer/array_mapper.rb", + "lib/solr/importer/delimited_file_source.rb", + "lib/solr/importer/hpricot_mapper.rb", + "lib/solr/importer/mapper.rb", + "lib/solr/importer/solr_source.rb", + "lib/solr/importer/xpath_mapper.rb", + "lib/solr/indexer.rb", + "lib/solr/request.rb", + "lib/solr/request/add_document.rb", + "lib/solr/request/base.rb", + "lib/solr/request/commit.rb", + "lib/solr/request/delete.rb", + "lib/solr/request/dismax.rb", + "lib/solr/request/index_info.rb", + "lib/solr/request/modify_document.rb", + "lib/solr/request/optimize.rb", + "lib/solr/request/ping.rb", + "lib/solr/request/select.rb", + "lib/solr/request/spellcheck.rb", + "lib/solr/request/standard.rb", + "lib/solr/request/update.rb", + "lib/solr/response.rb", + "lib/solr/response/add_document.rb", + "lib/solr/response/base.rb", + "lib/solr/response/commit.rb", + "lib/solr/response/delete.rb", + "lib/solr/response/dismax.rb", + "lib/solr/response/index_info.rb", + "lib/solr/response/modify_document.rb", + "lib/solr/response/optimize.rb", + "lib/solr/response/ping.rb", + "lib/solr/response/ruby.rb", + "lib/solr/response/select.rb", + "lib/solr/response/spellcheck.rb", + "lib/solr/response/standard.rb", + "lib/solr/response/xml.rb", + "lib/solr/solrtasks.rb", + "lib/solr/util.rb", + "lib/solr/xml.rb", + "lib/tasks/database.rake", + "lib/tasks/solr.rake", + "lib/tasks/test.rake", + "test/config/solr.yml", + "test/db/connections/mysql/connection.rb", + "test/db/connections/sqlite/connection.rb", + "test/db/migrate/001_create_books.rb", + "test/db/migrate/002_create_movies.rb", + "test/db/migrate/003_create_categories.rb", + "test/db/migrate/004_create_electronics.rb", + "test/db/migrate/005_create_authors.rb", + "test/db/migrate/006_create_postings.rb", + "test/db/migrate/007_create_posts.rb", + "test/db/migrate/008_create_gadgets.rb", + "test/db/migrate/009_create_dynamic_attributes.rb", + "test/db/migrate/010_create_advertises.rb", + "test/db/migrate/011_create_locals.rb", + "test/db/test.db", + "test/fixtures/advertises.yml", + "test/fixtures/authors.yml", + "test/fixtures/books.yml", + "test/fixtures/categories.yml", + "test/fixtures/db_definitions/mysql.sql", + "test/fixtures/dynamic_attributes.yml", + "test/fixtures/electronics.yml", + "test/fixtures/locals.yml", + "test/fixtures/movies.yml", + "test/fixtures/postings.yml", + "test/functional/acts_as_solr_test.rb", + "test/functional/association_indexing_test.rb", + "test/functional/faceted_search_test.rb", + "test/functional/multi_solr_search_test.rb", + "test/models/advertise.rb", + "test/models/author.rb", + "test/models/book.rb", + "test/models/category.rb", + "test/models/document.rb", + "test/models/dynamic_attribute.rb", + "test/models/electronic.rb", + "test/models/gadget.rb", + "test/models/local.rb", + "test/models/movie.rb", + "test/models/novel.rb", + "test/models/post.rb", + "test/models/posting.rb", + "test/test_helper.rb", + "test/unit/acts_methods_shoulda.rb", + "test/unit/class_methods_shoulda.rb", + "test/unit/common_methods_shoulda.rb", + "test/unit/instance_methods_shoulda.rb", + "test/unit/lazy_document_shoulda.rb", + "test/unit/parser_instance.rb", + "test/unit/parser_methods_shoulda.rb", + "test/unit/solr_instance.rb", + "test/unit/test_helper.rb" + ] + s.homepage = %q{http://github.com/dcrec1/acts_as_solr_reloaded} + s.require_paths = ["lib"] + s.rubygems_version = %q{1.5.0} + s.summary = %q{This gem adds full text search capabilities and many other nifty features from Apache Solr to any Rails model.} + s.test_files = [ + "test/db/connections/mysql/connection.rb", + "test/db/connections/sqlite/connection.rb", + "test/db/migrate/001_create_books.rb", + "test/db/migrate/002_create_movies.rb", + "test/db/migrate/003_create_categories.rb", + "test/db/migrate/004_create_electronics.rb", + "test/db/migrate/005_create_authors.rb", + "test/db/migrate/006_create_postings.rb", + "test/db/migrate/007_create_posts.rb", + "test/db/migrate/008_create_gadgets.rb", + "test/db/migrate/009_create_dynamic_attributes.rb", + "test/db/migrate/010_create_advertises.rb", + "test/db/migrate/011_create_locals.rb", + "test/functional/acts_as_solr_test.rb", + "test/functional/association_indexing_test.rb", + "test/functional/faceted_search_test.rb", + "test/functional/multi_solr_search_test.rb", + "test/models/advertise.rb", + "test/models/author.rb", + "test/models/book.rb", + "test/models/category.rb", + "test/models/document.rb", + "test/models/dynamic_attribute.rb", + "test/models/electronic.rb", + "test/models/gadget.rb", + "test/models/local.rb", + "test/models/movie.rb", + "test/models/novel.rb", + "test/models/post.rb", + "test/models/posting.rb", + "test/test_helper.rb", + "test/unit/acts_methods_shoulda.rb", + "test/unit/class_methods_shoulda.rb", + "test/unit/common_methods_shoulda.rb", + "test/unit/instance_methods_shoulda.rb", + "test/unit/lazy_document_shoulda.rb", + "test/unit/parser_instance.rb", + "test/unit/parser_methods_shoulda.rb", + "test/unit/solr_instance.rb", + "test/unit/test_helper.rb" + ] + + if s.respond_to? :specification_version then + s.specification_version = 3 + + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then + else + end + else + end +end + diff --git a/vendor/plugins/acts_as_solr_reloaded/config/solr.yml b/vendor/plugins/acts_as_solr_reloaded/config/solr.yml new file mode 100644 index 0000000..79779cf --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/config/solr.yml @@ -0,0 +1,14 @@ +# Config file for the acts_as_solr_reloaded plugin. +# +# If you change the host or port number here, make sure you update +# them in your Solr config file + +development: + url: http://127.0.0.1:8982/solr + +test: + url: http://127.0.0.1:8981/solr + +production: + url: http://127.0.0.1:8983/solr + jvm_options: -server -d64 -Xmx1024M -Xms64M \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/config/solr_environment.rb b/vendor/plugins/acts_as_solr_reloaded/config/solr_environment.rb new file mode 100644 index 0000000..b5d729b --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/config/solr_environment.rb @@ -0,0 +1,43 @@ +ENV['RAILS_ENV'] = (ENV['RAILS_ENV'] || 'development').dup +require "uri" +require "fileutils" +require "yaml" +dir = File.dirname(__FILE__) +SOLR_PATH = File.expand_path("#{dir}/../solr") unless defined? SOLR_PATH + +# RAILS_ROOT isn't defined yet, so figure it out. +unless defined? RAILS_ROOT + RAILS_ROOT = File.expand_path("#{File.dirname(__FILE__)}/../test") +end +unless defined? SOLR_LOGS_PATH + SOLR_LOGS_PATH = ENV["SOLR_LOGS_PATH"] || "#{RAILS_ROOT}/log" +end +unless defined? SOLR_PIDS_PATH + SOLR_PIDS_PATH = ENV["SOLR_PIDS_PATH"] || "#{RAILS_ROOT}/tmp/pids" +end +unless defined? SOLR_DATA_PATH + SOLR_DATA_PATH = ENV["SOLR_DATA_PATH"] || "#{RAILS_ROOT}/solr/#{ENV['RAILS_ENV']}" +end +unless defined? SOLR_CONFIG_PATH + SOLR_CONFIG_PATH = ENV["SOLR_CONFIG_PATH"] || "#{SOLR_PATH}/solr" +end +unless defined? SOLR_PID_FILE + SOLR_PID_FILE="#{SOLR_PIDS_PATH}/solr.#{ENV['RAILS_ENV']}.pid" +end + +unless defined? SOLR_PORT + config = YAML::load_file(RAILS_ROOT+'/config/solr.yml') + raise("No solr environment defined for RAILS_ENV the #{ENV['RAILS_ENV'].inspect}") unless config[ENV['RAILS_ENV']] + + SOLR_HOST = ENV['HOST'] || URI.parse(config[ENV['RAILS_ENV']]['url']).host + SOLR_PORT = ENV['PORT'] || URI.parse(config[ENV['RAILS_ENV']]['url']).port +end + +SOLR_JVM_OPTIONS = config[ENV['RAILS_ENV']]['jvm_options'] unless defined? SOLR_JVM_OPTIONS + +if ENV["ACTS_AS_SOLR_TEST"] + require "activerecord" + DB = (ENV['DB'] ? ENV['DB'] : 'sqlite') unless defined?(DB) + MYSQL_USER = (ENV['MYSQL_USER'].nil? ? 'root' : ENV['MYSQL_USER']) unless defined? MYSQL_USER + require File.join(File.dirname(File.expand_path(__FILE__)), '..', 'test', 'db', 'connections', DB, 'connection.rb') +end diff --git a/vendor/plugins/acts_as_solr_reloaded/generators/dynamic_attributes_migration/dynamic_attributes_migration_generator.rb b/vendor/plugins/acts_as_solr_reloaded/generators/dynamic_attributes_migration/dynamic_attributes_migration_generator.rb new file mode 100644 index 0000000..1292d0a --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/generators/dynamic_attributes_migration/dynamic_attributes_migration_generator.rb @@ -0,0 +1,7 @@ +class DynamicAttributesMigrationGenerator < Rails::Generator::Base + def manifest + record do |m| + m.migration_template 'migration.rb', 'db/migrate', :migration_file_name => "dynamic_attributes_migration" + end + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/generators/dynamic_attributes_migration/templates/migration.rb b/vendor/plugins/acts_as_solr_reloaded/generators/dynamic_attributes_migration/templates/migration.rb new file mode 100644 index 0000000..ab4a838 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/generators/dynamic_attributes_migration/templates/migration.rb @@ -0,0 +1,17 @@ +class DynamicAttributesMigration < ActiveRecord::Migration + def self.up + create_table :dynamic_attributes do |t| + t.integer :dynamicable_id + t.string :dynamicable_type + t.string :name + t.text :value + t.timestamps + end + add_index :dynamic_attributes, [:dynamicable_id, :dynamicable_type, :name], :unique => true, :name => 'da_pk' + end + + def self.down + remove_index 'da_pk' + drop_table :dynamic_attributes + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/generators/local_migration/local_migration_generator.rb b/vendor/plugins/acts_as_solr_reloaded/generators/local_migration/local_migration_generator.rb new file mode 100644 index 0000000..1458d43 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/generators/local_migration/local_migration_generator.rb @@ -0,0 +1,7 @@ +class LocalMigrationGenerator < Rails::Generator::Base + def manifest + record do |m| + m.migration_template 'migration.rb', 'db/migrate', :migration_file_name => "local_migration" + end + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/generators/local_migration/templates/migration.rb b/vendor/plugins/acts_as_solr_reloaded/generators/local_migration/templates/migration.rb new file mode 100644 index 0000000..66be240 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/generators/local_migration/templates/migration.rb @@ -0,0 +1,16 @@ +class LocalMigration < ActiveRecord::Migration + def self.up + create_table :locals do |t| + t.integer :localizable_id + t.string :localizable_type + t.string :latitude + t.string :longitude + + t.timestamps + end + end + + def self.down + drop_table :locals + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/init.rb b/vendor/plugins/acts_as_solr_reloaded/init.rb new file mode 100644 index 0000000..fb35c55 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/init.rb @@ -0,0 +1 @@ +require 'acts_as_solr' \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/install.rb b/vendor/plugins/acts_as_solr_reloaded/install.rb new file mode 100644 index 0000000..425a1d2 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/install.rb @@ -0,0 +1,5 @@ +require 'fileutils' + +src = File.join(File.dirname(__FILE__), 'config', 'solr.yml') +target = File.join(File.dirname(__FILE__), '..', '..', '..', 'config', 'solr.yml') +FileUtils.cp src, target \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr.rb b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr.rb new file mode 100644 index 0000000..402695f --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr.rb @@ -0,0 +1,47 @@ +require 'active_record' +require 'rexml/document' +require 'net/http' +require 'yaml' +require 'time' +require 'erb' +require 'rexml/xpath' + +require File.dirname(__FILE__) + '/solr' +require File.dirname(__FILE__) + '/acts_as_solr/acts_methods' +require File.dirname(__FILE__) + '/acts_as_solr/common_methods' +require File.dirname(__FILE__) + '/acts_as_solr/parser_methods' +require File.dirname(__FILE__) + '/acts_as_solr/class_methods' +require File.dirname(__FILE__) + '/acts_as_solr/dynamic_attribute' +require File.dirname(__FILE__) + '/acts_as_solr/local' +require File.dirname(__FILE__) + '/acts_as_solr/instance_methods' +require File.dirname(__FILE__) + '/acts_as_solr/common_methods' +require File.dirname(__FILE__) + '/acts_as_solr/deprecation' +require File.dirname(__FILE__) + '/acts_as_solr/search_results' +require File.dirname(__FILE__) + '/acts_as_solr/lazy_document' +require File.dirname(__FILE__) + '/acts_as_solr/mongo_mapper' + +module ActsAsSolr + class Post + class << self + def config + @config ||= YAML::load_file("#{Rails.root}/config/solr.yml")[Rails.env] + end + + def credentials + @credentials ||= {:username => config['username'], :password => config['password']} + end + + def url(core) + core.nil? ? config['url'] : "#{config['url']}/#{core}" + end + + def execute(request, core = nil) + connection = Solr::Connection.new(url(core), credentials) + connection.send request + end + end + end +end + +# reopen ActiveRecord and include the acts_as_solr method +ActiveRecord::Base.extend ActsAsSolr::ActsMethods diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/acts_methods.rb b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/acts_methods.rb new file mode 100644 index 0000000..25900df --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/acts_methods.rb @@ -0,0 +1,373 @@ +module ActsAsSolr #:nodoc: + + module ActsMethods + + # declares a class as solr-searchable + # + # ==== options: + # fields:: This option can be used to specify only the fields you'd + # like to index. If not given, all the attributes from the + # class will be indexed. You can also use this option to + # include methods that should be indexed as fields + # + # class Movie < ActiveRecord::Base + # acts_as_solr :fields => [:name, :description, :current_time] + # def current_time + # Time.now.to_s + # end + # end + # + # Each field passed can also be a hash with the value being a field type + # + # class Electronic < ActiveRecord::Base + # acts_as_solr :fields => [{:price => :range_float}] + # def current_time + # Time.now + # end + # end + # + # The field types accepted are: + # + # :float:: Index the field value as a float (ie.: 12.87) + # :integer:: Index the field value as an integer (ie.: 31) + # :boolean:: Index the field value as a boolean (ie.: true/false) + # :date:: Index the field value as a date (ie.: Wed Nov 15 23:13:03 PST 2006) + # :string:: Index the field value as a text string, not applying the same indexing + # filters as a regular text field + # :range_integer:: Index the field value for integer range queries (ie.:[5 TO 20]) + # :range_float:: Index the field value for float range queries (ie.:[14.56 TO 19.99]) + # + # Setting the field type preserves its original type when indexed + # + # The field may also be passed with a hash value containing options + # + # class Author < ActiveRecord::Base + # acts_as_solr :fields => [{:full_name => {:type => :text, :as => :name}}] + # def full_name + # self.first_name + ' ' + self.last_name + # end + # end + # + # The options accepted are: + # + # :type:: Index the field using the specified type + # :as:: Index the field using the specified field name + # + # additional_fields:: This option takes fields to be include in the index + # in addition to those derived from the database. You + # can also use this option to include custom fields + # derived from methods you define. This option will be + # ignored if the :fields option is given. It also accepts + # the same field types as the option above + # + # class Movie < ActiveRecord::Base + # acts_as_solr :additional_fields => [:current_time] + # def current_time + # Time.now.to_s + # end + # end + # + # exclude_fields:: This option taks an array of fields that should be ignored from indexing: + # + # class User < ActiveRecord::Base + # acts_as_solr :exclude_fields => [:password, :login, :credit_card_number] + # end + # + # include:: This option can be used for association indexing, which + # means you can include any :has_one, :has_many, :belongs_to + # and :has_and_belongs_to_many association to be indexed: + # + # class Category < ActiveRecord::Base + # has_many :books + # acts_as_solr :include => [:books] + # end + # + # Each association may also be specified as a hash with an option hash as a value + # + # class Book < ActiveRecord::Base + # belongs_to :author + # has_many :distribution_companies + # has_many :copyright_dates + # has_many :media_types + # acts_as_solr( + # :fields => [:name, :description], + # :include => [ + # {:author => {:using => :fullname, :as => :name}}, + # {:media_types => {:using => lambda{|media| type_lookup(media.id)}}} + # {:distribution_companies => {:as => :distributor, :multivalued => true}}, + # {:copyright_dates => {:as => :copyright, :type => :date}} + # ] + # ] + # + # The options accepted are: + # + # :type:: Index the associated objects using the specified type + # :as:: Index the associated objects using the specified field name + # :using:: Index the associated objects using the value returned by the specified method or proc. If a method + # symbol is supplied, it will be sent to each object to look up the value to index; if a proc is + # supplied, it will be called once for each object with the object as the only argument + # :multivalued:: Index the associated objects using one field for each object rather than joining them + # all into a single field + # + # facets:: This option can be used to specify the fields you'd like to + # index as facet fields + # + # class Electronic < ActiveRecord::Base + # acts_as_solr :facets => [:category, :manufacturer] + # end + # + # boost:: You can pass a boost (float) value that will be used to boost the document and/or a field. To specify a more + # boost for the document, you can either pass a block or a symbol. The block will be called with the record + # as an argument, a symbol will result in the according method being called: + # + # class Electronic < ActiveRecord::Base + # acts_as_solr :fields => [{:price => {:boost => 5.0}}], :boost => 10.0 + # end + # + # class Electronic < ActiveRecord::Base + # acts_as_solr :fields => [{:price => {:boost => 5.0}}], :boost => proc {|record| record.id + 120*37} + # end + # + # class Electronic < ActiveRecord::Base + # acts_as_solr :fields => [{:price => {:boost => :price_rating}}], :boost => 10.0 + # end + # + # if:: Only indexes the record if the condition evaluated is true. The argument has to be + # either a symbol, string (to be eval'ed), proc/method, or class implementing a static + # validation method. It behaves the same way as ActiveRecord's :if option. + # + # class Electronic < ActiveRecord::Base + # acts_as_solr :if => proc{|record| record.is_active?} + # end + # + # offline:: Assumes that your using an outside mechanism to explicitly trigger indexing records, e.g. you only + # want to update your index through some asynchronous mechanism. Will accept either a boolean or a block + # that will be evaluated before actually contacting the index for saving or destroying a document. Defaults + # to false. It doesn't refer to the mechanism of an offline index in general, but just to get a centralized point + # where you can control indexing. Note: This is only enabled for saving records. acts_as_solr doesn't always like + # it, if you have a different number of results coming from the database and the index. This might be rectified in + # another patch to support lazy loading. + # + # class Electronic < ActiveRecord::Base + # acts_as_solr :offline => proc {|record| record.automatic_indexing_disabled?} + # end + # + # auto_commit:: The commit command will be sent to Solr only if its value is set to true: + # + # class Author < ActiveRecord::Base + # acts_as_solr :auto_commit => false + # end + # + # dynamic_attributes: Default false. When true, requires a has_many relationship to a DynamicAttribute + # (:name, :value) model. Then, all dynamic attributes will be mapped as normal attributes + # in Solr, so you can filter like this: Model.find_by_solr "#{dynamic_attribute.name}:Lorem" + # taggable: Default false. When true, indexes tags with field name tag. Tags are taken from taggings.tag + # spatial: Default false. When true, indexes model.local.latitude and model.local.longitude as coordinates. + def acts_as_solr(options={}, solr_options={}, &deferred_solr_configuration) + + extend ClassMethods + include InstanceMethods + include CommonMethods + include ParserMethods + + define_solr_configuration_methods + + acts_as_taggable_on :tags if options[:taggable] + has_many :dynamic_attributes, :as => "dynamicable" if options[:dynamic_attributes] + has_one :local, :as => "localizable" if options[:spatial] + + after_save :solr_save + after_destroy :solr_destroy + + if deferred_solr_configuration + self.deferred_solr_configuration = deferred_solr_configuration + else + process_acts_as_solr(options, solr_options) + end + end + + def process_acts_as_solr(options, solr_options) + process_solr_options(options, solr_options) + end + + def define_solr_configuration_methods + # I'd like to use cattr_accessor, but it does not support lazy loaders and delegation to the class in the instance methods. + # TODO: Reconcile with cattr_accessor, or a more appropriate method. + class_eval(<<-EOS, __FILE__, __LINE__) + @@configuration = nil unless defined?(@@configuration) + @@solr_configuration = nil unless defined?(@@solr_configuration) + @@deferred_solr_configuration = nil unless defined?(@@deferred_solr_configuration) + + def self.configuration + return @@configuration if @@configuration + process_deferred_solr_configuration + @@configuration + end + def configuration + self.class.configuration + end + def self.configuration=(value) + @@configuration = value + end + def configuration=(value) + self.class.configuration = value + end + + def self.solr_configuration + return @@solr_configuration if @@solr_configuration + process_deferred_solr_configuration + @@solr_configuration + end + def solr_configuration + self.class.solr_configuration + end + def self.solr_configuration=(value) + @@solr_configuration = value + end + def solr_configuration=(value) + self.class.solr_configuration = value + end + + def self.deferred_solr_configuration + return @@deferred_solr_configuration if @@deferred_solr_configuration + @@deferred_solr_configuration + end + def deferred_solr_configuration + self.class.deferred_solr_configuration + end + def self.deferred_solr_configuration=(value) + @@deferred_solr_configuration = value + end + def deferred_solr_configuration=(value) + self.class.deferred_solr_configuration = value + end + EOS + end + + def process_deferred_solr_configuration + return unless deferred_solr_configuration + options, solr_options = deferred_solr_configuration.call + self.deferred_solr_configuration = nil + self.process_solr_options(options, solr_options) + end + + def process_solr_options(options={}, solr_options={}) + self.configuration = { + :fields => nil, + :additional_fields => nil, + :dynamic_attributes => false, + :exclude_fields => [], + :auto_commit => true, + :include => nil, + :facets => nil, + :boost => nil, + :if => "true", + :offline => false, + :spatial => false + } + self.solr_configuration = { + :type_field => "type_s", + :primary_key_field => "pk_s", + :default_boost => 1.0 + } + + configuration.update(options) if options.is_a?(Hash) + solr_configuration.update(solr_options) if solr_options.is_a?(Hash) + Deprecation.validate_index(configuration) + + configuration[:solr_fields] = {} + configuration[:solr_includes] = {} + + if configuration[:fields].respond_to?(:each) + process_fields(configuration[:fields]) + else + process_fields(self.new.attributes.keys.map { |k| k.to_sym }) + process_fields(configuration[:additional_fields]) + end + + if configuration[:include].respond_to?(:each) + process_includes(configuration[:include]) + end + end + + private + + def get_field_value(field) + field_name, options = determine_field_name_and_options(field) + configuration[:solr_fields][field_name] = options + + define_method("#{field_name}_for_solr".to_sym) do + begin + value = self[field_name] || self.instance_variable_get("@#{field_name.to_s}".to_sym) || self.send(field_name.to_sym) + case options[:type] + # format dates properly; return nil for nil dates + when :date + value ? (value.respond_to?(:utc) ? value.utc : value).strftime("%Y-%m-%dT%H:%M:%SZ") : nil + else value + end + rescue + puts $! + logger.debug "There was a problem getting the value for the field '#{field_name}': #{$!}" + value = '' + end + end + end + + def process_fields(raw_field) + if raw_field.respond_to?(:each) + raw_field.each do |field| + next if configuration[:exclude_fields].include?(field) + get_field_value(field) + end + end + end + + def process_includes(includes) + if includes.respond_to?(:each) + includes.each do |assoc| + field_name, options = determine_field_name_and_options(assoc) + configuration[:solr_includes][field_name] = options + end + end + end + + def determine_field_name_and_options(field) + if field.is_a?(Hash) + name = field.keys.first + options = field.values.first + if options.is_a?(Hash) + [name, {:type => type_for_field(field)}.merge(options)] + else + [name, {:type => options}] + end + else + [field, {:type => type_for_field(field)}] + end + end + + def type_for_field(field) + if configuration[:facets] && configuration[:facets].include?(field) + :facet + elsif column = columns_hash[field.to_s] + column_type = format_column_type(column.type) + + case column_type + when :string then :text + when :datetime then :date + when :time then :date + else column_type + end + else + :text + end + end + + def format_column_type(type) + if type.class.eql? Symbol + type + else + type.to_s.eql?("ObjectId") ? :string : type.to_s.downcase.to_sym + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/class_methods.rb b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/class_methods.rb new file mode 100644 index 0000000..b7caccf --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/class_methods.rb @@ -0,0 +1,242 @@ +module ActsAsSolr #:nodoc: + + module ClassMethods + include CommonMethods + include ParserMethods + + # Finds instances of a model. Terms are ANDed by default, can be overwritten + # by using OR between terms + # + # Here's a sample (untested) code for your controller: + # + # def search + # results = Book.find_by_solr params[:query] + # end + # + # You can also search for specific fields by searching for 'field:value' + # + # ====options: + # offset:: - The first document to be retrieved (offset) + # page:: - The page to be retrieved + # limit:: - The number of rows per page + # per_page:: - Alias for limit + # order:: - Orders (sort by) the result set using a given criteria: + # + # Book.find_by_solr 'ruby', :order => 'description asc' + # + # field_types:: This option is deprecated and will be obsolete by version 1.0. + # There's no need to specify the :field_types anymore when doing a + # search in a model that specifies a field type for a field. The field + # types are automatically traced back when they're included. + # + # class Electronic < ActiveRecord::Base + # acts_as_solr :fields => [{:price => :range_float}] + # end + # + # facets:: This option argument accepts the following arguments: + # fields:: The fields to be included in the faceted search (Solr's facet.field) + # query:: The queries to be included in the faceted search (Solr's facet.query) + # zeros:: Display facets with count of zero. (true|false) + # sort:: Sorts the faceted resuls by highest to lowest count. (true|false) + # browse:: This is where the 'drill-down' of the facets work. Accepts an array of + # fields in the format "facet_field:term" + # mincount:: Replacement for zeros (it has been deprecated in Solr). Specifies the + # minimum count necessary for a facet field to be returned. (Solr's + # facet.mincount) Overrides :zeros if it is specified. Default is 0. + # + # dates:: Run date faceted queries using the following arguments: + # fields:: The fields to be included in the faceted date search (Solr's facet.date). + # It may be either a String/Symbol or Hash. If it's a hash the options are the + # same as date_facets minus the fields option (i.e., :start:, :end, :gap, :other, + # :between). These options if provided will override the base options. + # (Solr's f..date.=). + # start:: The lower bound for the first date range for all Date Faceting. Required if + # :fields is present + # end:: The upper bound for the last date range for all Date Faceting. Required if + # :fields is prsent + # gap:: The size of each date range expressed as an interval to be added to the lower + # bound using the DateMathParser syntax. Required if :fields is prsent + # hardend:: A Boolean parameter instructing Solr what do do in the event that + # facet.date.gap does not divide evenly between facet.date.start and facet.date.end. + # other:: This param indicates that in addition to the counts for each date range + # constraint between facet.date.start and facet.date.end, other counds should be + # calculated. May specify more then one in an Array. The possible options are: + # before:: - all records with lower bound less than start + # after:: - all records with upper bound greater than end + # between:: - all records with field values between start and end + # none:: - compute no other bounds (useful in per field assignment) + # all:: - shortcut for before, after, and between + # filter:: Similar to :query option provided by :facets, in that accepts an array of + # of date queries to limit results. Can not be used as a part of a :field hash. + # This is the only option that can be used if :fields is not present. + # + # Example: + # + # Electronic.find_by_solr "memory", :facets => {:zeros => false, :sort => true, + # :query => ["price:[* TO 200]", + # "price:[200 TO 500]", + # "price:[500 TO *]"], + # :fields => [:category, :manufacturer], + # :browse => ["category:Memory","manufacturer:Someone"]} + # + # + # Examples of date faceting: + # + # basic: + # Electronic.find_by_solr "memory", :facets => {:dates => {:fields => [:updated_at, :created_at], + # :start => 'NOW-10YEARS/DAY', :end => 'NOW/DAY', :gap => '+2YEARS', :other => :before}} + # + # advanced: + # Electronic.find_by_solr "memory", :facets => {:dates => {:fields => [:updated_at, + # {:created_at => {:start => 'NOW-20YEARS/DAY', :end => 'NOW-10YEARS/DAY', :other => [:before, :after]} + # }], :start => 'NOW-10YEARS/DAY', :end => 'NOW/DAY', :other => :before, :filter => + # ["created_at:[NOW-10YEARS/DAY TO NOW/DAY]", "updated_at:[NOW-1YEAR/DAY TO NOW/DAY]"]}} + # + # filter only: + # Electronic.find_by_solr "memory", :facets => {:dates => {:filter => "updated_at:[NOW-1YEAR/DAY TO NOW/DAY]"}} + # + # + # + # scores:: If set to true this will return the score as a 'solr_score' attribute + # for each one of the instances found. Does not currently work with find_id_by_solr + # + # books = Book.find_by_solr 'ruby OR splinter', :scores => true + # books.records.first.solr_score + # => 1.21321397 + # books.records.last.solr_score + # => 0.12321548 + # + # lazy:: If set to true the search will return objects that will touch the database when you ask for one + # of their attributes for the first time. Useful when you're using fragment caching based solely on + # types and ids. + # + # relevance:: Sets fields relevance + # + # Book.find_by_solr "zidane", :relevance => {:title => 5, :author => 2} + # + def find_by_solr(query, options={}) + data = parse_query(query, options) + return parse_results(data, options) + end + alias :search :find_by_solr + + # Finds instances of a model and returns an array with the ids: + # Book.find_id_by_solr "rails" => [1,4,7] + # The options accepted are the same as find_by_solr + # + def find_id_by_solr(query, options={}) + data = parse_query(query, options) + return parse_results(data, {:format => :ids}) + end + + # This method can be used to execute a search across multiple models: + # Book.multi_solr_search "Napoleon OR Tom", :models => [Movie] + # + # ====options: + # Accepts the same options as find_by_solr plus: + # models:: The additional models you'd like to include in the search + # results_format:: Specify the format of the results found + # :objects :: Will return an array with the results being objects (default). Example: + # Book.multi_solr_search "Napoleon OR Tom", :models => [Movie], :results_format => :objects + # :ids :: Will return an array with the ids of each entry found. Example: + # Book.multi_solr_search "Napoleon OR Tom", :models => [Movie], :results_format => :ids + # => [{"id" => "Movie:1"},{"id" => Book:1}] + # Where the value of each array is as Model:instance_id + # scores:: If set to true this will return the score as a 'solr_score' attribute + # for each one of the instances found. Does not currently work with find_id_by_solr + # + # books = Book.multi_solr_search 'ruby OR splinter', :scores => true + # books.records.first.solr_score + # => 1.21321397 + # books.records.last.solr_score + # => 0.12321548 + # + def multi_solr_search(query, options = {}) + models = multi_model_suffix(options) + options.update(:results_format => :objects) unless options[:results_format] + data = parse_query(query, options, models) + + if data.nil? or data.total_hits == 0 + return SearchResults.new(:docs => [], :total => 0) + end + + result = find_multi_search_objects(data, options) + if options[:scores] and options[:results_format] == :objects + add_scores(result, data) + end + SearchResults.new :docs => result, :total => data.total_hits + end + + def find_multi_search_objects(data, options) + result = [] + if options[:results_format] == :objects + data.hits.each do |doc| + k = doc.fetch('id').first.to_s.split(':') + result << k[0].constantize.find_by_id(k[1]) + end + elsif options[:results_format] == :ids + data.hits.each{|doc| result << {"id" => doc["id"].to_s}} + end + result + end + + def multi_model_suffix(options) + models = "AND (#{solr_configuration[:type_field]}:\"#{self.name}\"" + models << " OR " + options[:models].collect {|m| "#{solr_configuration[:type_field]}:\"" + m.to_s + "\""}.join(" OR ") if options[:models].is_a?(Array) + models << ")" + end + + # returns the total number of documents found in the query specified: + # Book.count_by_solr 'rails' => 3 + # + def count_by_solr(query, options = {}) + data = parse_query(query, options) + data.total_hits + end + + # It's used to rebuild the Solr index for a specific model. + # Book.rebuild_solr_index + # + # If batch_size is greater than 0, adds will be done in batches. + # NOTE: If using sqlserver, be sure to use a finder with an explicit order. + # Non-edge versions of rails do not handle pagination correctly for sqlserver + # without an order clause. + # + # If a finder block is given, it will be called to retrieve the items to index. + # This can be very useful for things such as updating based on conditions or + # using eager loading for indexed associations. + def rebuild_solr_index(batch_size=100, &finder) + finder ||= lambda { |ar, options| ar.find(:all, options.merge({:order => self.primary_key})) } + start_time = Time.now + + if batch_size > 0 + items_processed = 0 + limit = batch_size + offset = 0 + begin + iteration_start = Time.now + items = finder.call(self, {:limit => limit, :offset => offset}) + add_batch = items.collect { |content| content.to_solr_doc } + + if items.size > 0 + solr_add add_batch + solr_commit + end + + items_processed += items.size + last_id = items.last.id if items.last + time_so_far = Time.now - start_time + iteration_time = Time.now - iteration_start + logger.info "#{Process.pid}: #{items_processed} items for #{self.name} have been batch added to index in #{'%.3f' % time_so_far}s at #{'%.3f' % (items_processed / time_so_far)} items/sec (#{'%.3f' % (items.size / iteration_time)} items/sec for the last batch). Last id: #{last_id}" + offset += items.size + end while items.nil? || items.size > 0 + else + items = finder.call(self, {}) + items.each { |content| content.solr_save } + items_processed = items.size + end + solr_optimize + logger.info items_processed > 0 ? "Index for #{self.name} has been rebuilt" : "Nothing to index for #{self.name}" + end + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/common_methods.rb b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/common_methods.rb new file mode 100644 index 0000000..afd404d --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/common_methods.rb @@ -0,0 +1,87 @@ +module ActsAsSolr #:nodoc: + + module CommonMethods + + # Converts field types into Solr types + def get_solr_field_type(field_type) + if field_type.is_a?(Symbol) + case field_type + when :float + return "f" + when :integer + return "i" + when :boolean + return "b" + when :string + return "s" + when :date + return "d" + when :range_float + return "rf" + when :range_integer + return "ri" + when :facet + return "facet" + when :text + return "t" + else + raise "Unknown field_type symbol: #{field_type}" + end + elsif field_type.is_a?(String) + return field_type + else + raise "Unknown field_type class: #{field_type.class}: #{field_type}" + end + end + + # Sets a default value when value being set is nil. + def set_value_if_nil(field_type) + case field_type + when "b", :boolean + return "false" + when "s", "t", "d", :date, :string, :text + return "" + when "f", "rf", :float, :range_float + return 0.00 + when "i", "ri", :integer, :range_integer + return 0 + else + return "" + end + end + + # Sends an add command to Solr + def solr_add(add_xml) + ActsAsSolr::Post.execute(Solr::Request::AddDocument.new(add_xml)) + end + + # Sends the delete command to Solr + def solr_delete(solr_ids) + ActsAsSolr::Post.execute(Solr::Request::Delete.new(:id => solr_ids)) + end + + # Sends the commit command to Solr + def solr_commit + ActsAsSolr::Post.execute(Solr::Request::Commit.new) + end + + # Optimizes the Solr index. Solr says: + # + # Optimizations can take nearly ten minutes to run. + # We are presuming optimizations should be run once following large + # batch-like updates to the collection and/or once a day. + # + # One of the solutions for this would be to create a cron job that + # runs every day at midnight and optmizes the index: + # 0 0 * * * /your_rails_dir/script/runner -e production "Model.solr_optimize" + # + def solr_optimize + ActsAsSolr::Post.execute(Solr::Request::Optimize.new) + end + + # Returns the id for the given instance + def record_id(object) + eval "object.#{object.class.primary_key}" + end + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/deprecation.rb b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/deprecation.rb new file mode 100644 index 0000000..94d2194 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/deprecation.rb @@ -0,0 +1,61 @@ +module ActsAsSolr #:nodoc: + + class Post + def initialize(body, mode = :search) + @body = body + @mode = mode + puts "The method ActsAsSolr::Post.new(body, mode).execute_post is depracated. " + + "Use ActsAsSolr::Post.execute(body, mode) instead!" + end + + def execute_post + ActsAsSolr::Post.execute(@body, @mode) + end + end + + module ClassMethods + def find_with_facet(query, options={}) + Deprecation.plog "The method find_with_facet is deprecated. Use find_by_solr instead, passing the " + + "arguments the same way you used to do with find_with_facet." + find_by_solr(query, options) + end + end + + class Deprecation + # Validates the options passed during query + def self.validate_query options={} + if options[:field_types] + plog "The option :field_types for searching is deprecated. " + + "The field types are automatically traced back when you specify a field type in your model." + end + if options[:sort_by] + plog "The option :sort_by is deprecated, use :order instead!" + options[:order] ||= options[:sort_by] + end + if options[:start] + plog "The option :start is deprecated, use :offset instead!" + options[:offset] ||= options[:start] + end + if options[:rows] + plog "The option :rows is deprecated, use :limit instead!" + options[:limit] ||= options[:rows] + end + end + + # Validates the options passed during indexing + def self.validate_index options={} + if options[:background] + plog "The :background option is being deprecated. There are better and more efficient " + + "ways to handle delayed saving of your records." + end + end + + # This will print the text to stdout and log the text + # if rails logger is available + def self.plog text + puts text + RAILS_DEFAULT_LOGGER.warn text if defined? RAILS_DEFAULT_LOGGER + end + end + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/dynamic_attribute.rb b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/dynamic_attribute.rb new file mode 100644 index 0000000..29f8d2c --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/dynamic_attribute.rb @@ -0,0 +1,3 @@ +class DynamicAttribute < ActiveRecord::Base + belongs_to :dynamicable, :polymorphic => true +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/instance_methods.rb b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/instance_methods.rb new file mode 100644 index 0000000..31031e8 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/instance_methods.rb @@ -0,0 +1,196 @@ +module ActsAsSolr #:nodoc: + + module InstanceMethods + + # Solr id is : to be unique across all models + def solr_id + "#{self.class.name}:#{record_id(self)}" + end + + # saves to the Solr index + def solr_save + return true if indexing_disabled? + if evaluate_condition(:if, self) + debug "solr_save: #{self.class.name} : #{record_id(self)}" + solr_add to_solr_doc + solr_commit if configuration[:auto_commit] + true + else + solr_destroy + end + end + + def indexing_disabled? + evaluate_condition(:offline, self) || !configuration[:if] + end + + # remove from index + def solr_destroy + return true if indexing_disabled? + debug "solr_destroy: #{self.class.name} : #{record_id(self)}" + solr_delete solr_id + solr_commit if configuration[:auto_commit] + true + end + + # convert instance to Solr document + def to_solr_doc + debug "to_solr_doc: creating doc for class: #{self.class.name}, id: #{record_id(self)}" + doc = Solr::Document.new + doc.boost = validate_boost(configuration[:boost]) if configuration[:boost] + + doc << {:id => solr_id, + solr_configuration[:type_field] => self.class.name, + solr_configuration[:primary_key_field] => record_id(self).to_s} + + # iterate through the fields and add them to the document, + configuration[:solr_fields].each do |field_name, options| + #field_type = configuration[:facets] && configuration[:facets].include?(field) ? :facet : :text + + field_boost = options[:boost] || solr_configuration[:default_boost] + field_type = get_solr_field_type(options[:type]) + solr_name = options[:as] || field_name + + value = self.send("#{field_name}_for_solr") + value = set_value_if_nil(field_type) if value.to_s == "" + + # add the field to the document, but only if it's not the id field + # or the type field (from single table inheritance), since these + # fields have already been added above. + if field_name.to_s != self.class.primary_key and field_name.to_s != "type" + suffix = get_solr_field_type(field_type) + # This next line ensures that e.g. nil dates are excluded from the + # document, since they choke Solr. Also ignores e.g. empty strings, + # but these can't be searched for anyway: + # http://www.mail-archive.com/solr-dev@lucene.apache.org/msg05423.html + next if value.nil? || value.to_s.strip.empty? + [value].flatten.each do |v| + v = set_value_if_nil(suffix) if value.to_s == "" + field = Solr::Field.new("#{solr_name}_#{suffix}" => ERB::Util.html_escape(v.to_s)) + field.boost = validate_boost(field_boost) + doc << field + end + end + end + + add_dynamic_attributes(doc) + add_includes(doc) + add_tags(doc) + add_space(doc) + + debug doc.to_xml + doc + end + + private + + def debug(text) + logger.debug text rescue nil + end + + def add_space(doc) + if configuration[:spatial] and local + doc << Solr::Field.new("lat" => local.latitude) + doc << Solr::Field.new("lng" => local.longitude) + end + end + + def add_tags(doc) + taggings.each do |tagging| + doc << Solr::Field.new("tag_facet" => tagging.tag.name) + doc << Solr::Field.new("tag_t" => tagging.tag.name) + end if configuration[:taggable] + end + + def add_dynamic_attributes(doc) + dynamic_attributes.each do |attribute| + value = ERB::Util.html_escape(attribute.value) + doc << Solr::Field.new("#{attribute.name}_t" => value) + doc << Solr::Field.new("#{attribute.name}_facet" => value) + end if configuration[:dynamic_attributes] + end + + def add_includes(doc) + if configuration[:solr_includes].respond_to?(:each) + configuration[:solr_includes].each do |association, options| + data = options[:multivalued] ? [] : "" + field_name = options[:as] || association.to_s.singularize + field_type = get_solr_field_type(options[:type]) + field_boost = options[:boost] || solr_configuration[:default_boost] + suffix = get_solr_field_type(field_type) + case self.class.reflect_on_association(association).macro + when :has_many, :has_and_belongs_to_many + records = self.send(association).to_a + unless records.empty? + records.each {|r| data << include_value(r, options)} + [data].flatten.each do |value| + field = Solr::Field.new("#{field_name}_#{suffix}" => value) + field.boost = validate_boost(field_boost) + doc << field + end + end + when :has_one, :belongs_to + record = self.send(association) + unless record.nil? + doc["#{field_name}_#{suffix}"] = include_value(record, options) + end + end + end + end + end + + def include_value(record, options) + if options[:using].is_a? Proc + options[:using].call(record) + elsif options[:using].is_a? Symbol + record.send(options[:using]) + else + record.attributes.inject([]){|k,v| k << "#{v.first}=#{ERB::Util.html_escape(v.last)}"}.join(" ") + end + end + + def validate_boost(boost) + boost_value = case boost + when Float + return solr_configuration[:default_boost] if boost < 0 + boost + when Proc + boost.call(self) + when Symbol + if self.respond_to?(boost) + self.send(boost) + end + end + + boost_value || solr_configuration[:default_boost] + end + + def condition_block?(condition) + condition.respond_to?("call") && (condition.arity == 1 || condition.arity == -1) + end + + def evaluate_condition(which_condition, field) + condition = configuration[which_condition] + case condition + when Symbol + field.send(condition) + when String + eval(condition, binding) + when FalseClass, NilClass + false + when TrueClass + true + else + if condition_block?(condition) + condition.call(field) + else + raise( + ArgumentError, + "The :#{which_condition} option has to be either a symbol, string (to be eval'ed), proc/method, true/false, or " + + "class implementing a static validation method" + ) + end + end + end + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/lazy_document.rb b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/lazy_document.rb new file mode 100644 index 0000000..8cf8960 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/lazy_document.rb @@ -0,0 +1,18 @@ +module ActsAsSolr + class LazyDocument + attr_reader :id, :clazz + + def initialize(id, clazz) + @id = id + @clazz = clazz + end + + def method_missing(name, *args) + unless @__instance + @__instance = @clazz.find(@id) + end + + @__instance.send(name, *args) + end + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/local.rb b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/local.rb new file mode 100644 index 0000000..618e5bc --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/local.rb @@ -0,0 +1,4 @@ +class Local < ActiveRecord::Base + belongs_to :localizable, :polymorphic => true + validates_presence_of :latitude, :longitude +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/mongo_mapper.rb b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/mongo_mapper.rb new file mode 100644 index 0000000..0015f4b --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/mongo_mapper.rb @@ -0,0 +1,27 @@ +module ActsAsSolr + module MongoMapper + def self.included(clazz) + clazz.extend ActsAsSolr::ActsMethods + clazz.extend ClassMethods + end + + module ClassMethods + def columns_hash + keys + end + + def primary_key + 'id' + end + + def find(*args) + if args.first.instance_of? Array + ids = args.first.map { |id| Mongo::ObjectID.from_string(id) } + super :all, :conditions => {primary_key => ids} + else + super *args + end + end + end + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/parser_methods.rb b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/parser_methods.rb new file mode 100644 index 0000000..2b25a24 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/parser_methods.rb @@ -0,0 +1,260 @@ +module ActsAsSolr #:nodoc: + module ParserMethods + protected + + # Method used by mostly all the ClassMethods when doing a search + def parse_query(query=nil, options={}, models=nil) + valid_options = [ :offset, :limit, :facets, :models, :results_format, :order, + :scores, :operator, :include, :lazy, :joins, :select, :core, + :around, :relevance, :highlight, :page, :per_page] + query_options = {} + query = sanitize_query(query) if query + return nil if (query.nil? || query.strip == '') + + + raise "Invalid parameters: #{(options.keys - valid_options).join(',')}" unless (options.keys - valid_options).empty? + begin + Deprecation.validate_query(options) + per_page = options[:per_page] || options[:limit] || 30 + offset = options[:offset] || (((options[:page] || 1).to_i - 1) * per_page) + query_options[:rows] = per_page + query_options[:start] = offset + query_options[:operator] = options[:operator] + + query = add_relevance query, options[:relevance] + + # first steps on the facet parameter processing + if options[:facets] + query_options[:facets] = {} + query_options[:facets][:limit] = -1 # TODO: make this configurable + query_options[:facets][:sort] = :count if options[:facets][:sort] + query_options[:facets][:mincount] = 0 + query_options[:facets][:mincount] = 1 if options[:facets][:zeros] == false + # override the :zeros (it's deprecated anyway) if :mincount exists + query_options[:facets][:mincount] = options[:facets][:mincount] if options[:facets][:mincount] + query_options[:facets][:fields] = options[:facets][:fields].collect{|k| "#{k}_facet"} if options[:facets][:fields] + query_options[:filter_queries] = replace_types([*options[:facets][:browse]].collect{|k| "#{k.sub!(/ *: */,"_facet:")}"}) if options[:facets][:browse] + query_options[:facets][:queries] = replace_types(options[:facets][:query].collect{|k| "#{k.sub!(/ *: */,"_t:")}"}) if options[:facets][:query] + + + if options[:facets][:dates] + query_options[:date_facets] = {} + # if options[:facets][:dates][:fields] exists then :start, :end, and :gap must be there + if options[:facets][:dates][:fields] + [:start, :end, :gap].each { |k| raise "#{k} must be present in faceted date query" unless options[:facets][:dates].include?(k) } + query_options[:date_facets][:fields] = [] + options[:facets][:dates][:fields].each { |f| + if f.kind_of? Hash + key = f.keys[0] + query_options[:date_facets][:fields] << {"#{key}_d" => f[key]} + validate_date_facet_other_options(f[key][:other]) if f[key][:other] + else + query_options[:date_facets][:fields] << "#{f}_d" + end + } + end + + query_options[:date_facets][:start] = options[:facets][:dates][:start] if options[:facets][:dates][:start] + query_options[:date_facets][:end] = options[:facets][:dates][:end] if options[:facets][:dates][:end] + query_options[:date_facets][:gap] = options[:facets][:dates][:gap] if options[:facets][:dates][:gap] + query_options[:date_facets][:hardend] = options[:facets][:dates][:hardend] if options[:facets][:dates][:hardend] + query_options[:date_facets][:filter] = replace_types([*options[:facets][:dates][:filter]].collect{|k| "#{k.sub!(/ *:(?!\d) */,"_d:")}"}) if options[:facets][:dates][:filter] + + if options[:facets][:dates][:other] + validate_date_facet_other_options(options[:facets][:dates][:other]) + query_options[:date_facets][:other] = options[:facets][:dates][:other] + end + + end + end + + if models.nil? + # TODO: use a filter query for type, allowing Solr to cache it individually + models = "AND #{solr_type_condition}" + field_list = solr_configuration[:primary_key_field] + else + field_list = "id" + end + + query_options[:field_list] = [field_list, 'score'] + query = "(#{query.gsub(/ *: */,"_t:")}) #{models}" + order = options[:order].split(/\s*,\s*/).collect{|e| e.gsub(/\s+/,'_t ').gsub(/\bscore_t\b/, 'score') }.join(',') if options[:order] + query_options[:query] = replace_types([query])[0] # TODO adjust replace_types to work with String or Array + + if options[:highlight] + query_options[:highlighting] = {} + query_options[:highlighting][:field_list] = [] + query_options[:highlighting][:field_list] << options[:highlight][:fields].collect {|k| "#{k}_t"} if options[:highlight][:fields] + query_options[:highlighting][:require_field_match] = options[:highlight][:require_field_match] if options[:highlight][:require_field_match] + query_options[:highlighting][:max_snippets] = options[:highlight][:max_snippets] if options[:highlight][:max_snippets] + query_options[:highlighting][:prefix] = options[:highlight][:prefix] if options[:highlight][:prefix] + query_options[:highlighting][:suffix] = options[:highlight][:suffix] if options[:highlight][:suffix] + end + + # TODO: set the sort parameter instead of the old ;order. style. + query_options[:sort] = replace_types([order], false)[0] if options[:order] + + if options[:around] + query_options[:radius] = options[:around][:radius] + query_options[:latitude] = options[:around][:latitude] + query_options[:longitude] = options[:around][:longitude] + end + + ActsAsSolr::Post.execute(Solr::Request::Standard.new(query_options), options[:core]) + rescue + raise "There was a problem executing your search\n#{query_options.inspect}\n: #{$!} in #{$!.backtrace.first}" + end + end + + def solr_type_condition + (subclasses || []).inject("(#{solr_configuration[:type_field]}:\"#{self.name}\"") do |condition, subclass| + condition << (subclass.name.empty? ? "" : " OR #{solr_configuration[:type_field]}:\"#{subclass.name}\"") + end << ')' + end + + # Parses the data returned from Solr + def parse_results(solr_data, options = {}) + results = { + :docs => [], + :total => 0 + } + + configuration = { + :format => :objects + } + results.update(:spellcheck => solr_data.data['spellcheck']) unless solr_data.nil? + results.update(:facets => {'facet_fields' => []}) if options[:facets] + unless solr_data.nil? or solr_data.header['params'].nil? + header = solr_data.header + results.update :rows => header['params']['rows'] + results.update :start => header['params']['start'] + end + return SearchResults.new(results) if (solr_data.nil? || solr_data.total_hits == 0) + + configuration.update(options) if options.is_a?(Hash) + + ids = solr_data.hits.collect {|doc| doc["#{solr_configuration[:primary_key_field]}"]}.flatten + + result = find_objects(ids, options, configuration) + + add_scores(result, solr_data) if configuration[:format] == :objects && options[:scores] + + highlighted = {} + solr_data.highlighting.map do |x,y| + e={} + y1=y.map{|x1,y1| e[x1.gsub(/_[^_]*/,"")]=y1} unless y.nil? + highlighted[x.gsub(/[^:]*:/,"").to_i]=e + end unless solr_data.highlighting.nil? + + results.update(:facets => solr_data.data['facet_counts']) if options[:facets] + results.update({:docs => result, :total => solr_data.total_hits, :max_score => solr_data.max_score, :query_time => solr_data.data['responseHeader']['QTime']}) + results.update({:highlights=>highlighted}) + SearchResults.new(results) + end + + + def find_objects(ids, options, configuration) + result = if configuration[:lazy] && configuration[:format] != :ids + ids.collect {|id| ActsAsSolr::LazyDocument.new(id, self)} + elsif configuration[:format] == :objects + find_options = {} + find_options[:include] = options[:include] if options[:include] + find_options[:select] = options[:select] if options[:select] + find_options[:joins] = options[:joins] if options[:joins] + result = reorder(self.find(ids, find_options), ids) + else + ids + end + + result + end + + # Reorders the instances keeping the order returned from Solr + def reorder(things, ids) + ordered_things = [] + ids.each do |id| + thing = things.find { |t| t.id.to_s == id.to_s } + ordered_things |= [thing] if thing + end + ordered_things + end + + # Replaces the field types based on the types (if any) specified + # on the acts_as_solr call + def replace_types(strings, include_colon=true) + suffix = include_colon ? ":" : "" + if configuration[:solr_fields] + configuration[:solr_fields].each do |name, options| + solr_name = options[:as] || name.to_s + solr_type = get_solr_field_type(options[:type]) + field = "#{solr_name}_#{solr_type}#{suffix}" + strings.each_with_index {|s,i| strings[i] = s.gsub(/#{solr_name.to_s}_t#{suffix}/,field) } + end + end + if configuration[:solr_includes] + configuration[:solr_includes].each do |association, options| + solr_name = options[:as] || association.to_s.singularize + solr_type = get_solr_field_type(options[:type]) + field = "#{solr_name}_#{solr_type}#{suffix}" + strings.each_with_index {|s,i| strings[i] = s.gsub(/#{solr_name.to_s}_t#{suffix}/,field) } + end + end + strings + end + + # Adds the score to each one of the instances found + def add_scores(results, solr_data) + with_score = [] + solr_data.hits.each do |doc| + with_score.push([doc["score"], + results.find {|record| scorable_record?(record, doc) }]) + end + with_score.each do |score, object| + class << object; attr_accessor :solr_score; end + object.solr_score = score + end + end + + def scorable_record?(record, doc) + doc_id = doc["#{solr_configuration[:primary_key_field]}"] + if doc_id.nil? + doc_id = doc["id"] + "#{record.class.name}:#{record_id(record)}" == doc_id.first.to_s + else + record_id(record).to_s == doc_id.to_s + end + end + + def validate_date_facet_other_options(options) + valid_other_options = [:after, :all, :before, :between, :none] + options = [options] unless options.kind_of? Array + bad_options = options.map {|x| x.to_sym} - valid_other_options + raise "Invalid option#{'s' if bad_options.size > 1} for faceted date's other param: #{bad_options.join(', ')}. May only be one of :after, :all, :before, :between, :none" if bad_options.size > 0 + end + + # Remove all leading ?'s and *'s from query + def sanitize_query(query) + query.gsub(/\A([\?|\*| ]+)/, '') + end + + private + + def add_relevance(query, relevance) + return query if relevance.nil? + q = if query.include? ':' + q = query.split(":").first.split(" ") + q.pop + return query if q.empty? + q.join ' ' + else + query + end + relevance.each do |attribute, value| + query = "#{query} OR #{attribute}:(#{q})^#{value}" + end + query + end + + end +end + diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/search_results.rb b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/search_results.rb new file mode 100644 index 0000000..c8220bf --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/search_results.rb @@ -0,0 +1,94 @@ +module ActsAsSolr #:nodoc: + + # TODO: Possibly looking into hooking it up with Solr::Response::Standard + # + # Class that returns the search results with four methods. + # + # books = Book.find_by_solr 'ruby' + # + # the above will return a SearchResults class with 4 methods: + # + # docs|results|records: will return an array of records found + # + # books.records.empty? + # => false + # + # total|num_found|total_hits: will return the total number of records found + # + # books.total + # => 2 + # + # facets: will return the facets when doing a faceted search + # + # max_score|highest_score: returns the highest score found + # + # books.max_score + # => 1.3213213 + # + # + class SearchResults + def initialize(solr_data={}) + @solr_data = solr_data + end + + # Returns an array with the instances. This method + # is also aliased as docs and records + def results + @solr_data[:docs] + end + + # Returns the total records found. This method is + # also aliased as num_found and total_hits + def total + @solr_data[:total] + end + + # Returns the facets when doing a faceted search + def facets + @solr_data[:facets] + end + + # Returns the highest score found. This method is + # also aliased as highest_score + def max_score + @solr_data[:max_score] + end + + def query_time + @solr_data[:query_time] + end + + # Returns the highlighted fields which one has asked for.. + def highlights + @solr_data[:highlights] + end + + # Returns a suggested query + def suggest + @solr_data[:spellcheck]['suggestions']['collation'].match(/\((.+)\) /)[1] + end + + # Returns the number of documents per page + def per_page + @solr_data[:rows].to_i + end + + # Returns the number of pages found + def total_pages + (total / per_page.to_f).ceil + end + + # Returns the current page + def current_page + (@solr_data[:start].to_i / per_page) + 1 + end + + alias docs results + alias records results + alias num_found total + alias total_hits total + alias highest_score max_score + end + +end + diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/solr_fixtures.rb b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/solr_fixtures.rb new file mode 100644 index 0000000..c16781e --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/solr_fixtures.rb @@ -0,0 +1,13 @@ +module ActsAsSolr + + class SolrFixtures + def self.load(table_names) + [table_names].flatten.map { |n| n.to_s }.each do |table_name| + klass = instance_eval(File.split(table_name.to_s).last.to_s.gsub('_',' ').split(" ").collect{|w| w.capitalize}.to_s.singularize) + klass.rebuild_solr_index if klass.respond_to?(:rebuild_solr_index) + end + ActsAsSolr::Post.execute(Solr::Request::Commit.new) + end + end + +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/tasks.rb b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/tasks.rb new file mode 100644 index 0000000..f2a8d0b --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr/tasks.rb @@ -0,0 +1,10 @@ +dir = File.dirname(__FILE__) +require 'rubygems' +require 'rake' +require 'net/http' +require 'active_record' +require File.expand_path("#{dir}/solr_fixtures") + +load File.expand_path("#{dir}/tasks/database.rake") +load File.expand_path("#{dir}/tasks/solr.rake") +load File.expand_path("#{dir}/tasks/test.rake") diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr_reloaded.rb b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr_reloaded.rb new file mode 100644 index 0000000..fb35c55 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/acts_as_solr_reloaded.rb @@ -0,0 +1 @@ +require 'acts_as_solr' \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr.rb new file mode 100755 index 0000000..efdfee5 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr.rb @@ -0,0 +1,26 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Solr; end +require File.expand_path("#{File.dirname(__FILE__)}/solr/exception") +require File.expand_path("#{File.dirname(__FILE__)}/solr/request") +require File.expand_path("#{File.dirname(__FILE__)}/solr/connection") +require File.expand_path("#{File.dirname(__FILE__)}/solr/response") +require File.expand_path("#{File.dirname(__FILE__)}/solr/util") +require File.expand_path("#{File.dirname(__FILE__)}/solr/xml") +require File.expand_path("#{File.dirname(__FILE__)}/solr/importer") +require File.expand_path("#{File.dirname(__FILE__)}/solr/indexer") +require File.expand_path("#{File.dirname(__FILE__)}/solr/xml") +require File.expand_path("#{File.dirname(__FILE__)}/solr/field") +require File.expand_path("#{File.dirname(__FILE__)}/solr/request/base") +require File.expand_path("#{File.dirname(__FILE__)}/solr/document") +require File.expand_path("#{File.dirname(__FILE__)}/solr/request/update") diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/connection.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/connection.rb new file mode 100755 index 0000000..1adb92b --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/connection.rb @@ -0,0 +1,180 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# TODO: add a convenience method to POST a Solr .xml file, like Solr's example post.sh + +class Solr::Connection + attr_reader :url, :autocommit, :connection + + # create a connection to a solr instance using the url for the solr + # application context: + # + # conn = Solr::Connection.new("http://example.com:8080/solr") + # + # if you would prefer to have all adds/updates autocommitted, + # use :autocommit => :on + # + # conn = Solr::Connection.new('http://example.com:8080/solr', + # :autocommit => :on) + + def initialize(url="http://localhost:8983/solr", opts={}) + @url = URI.parse(url) + unless @url.kind_of? URI::HTTP + raise "invalid http url: #{url}" + end + + # TODO: Autocommit seems nice at one level, but it currently is confusing because + # only calls to Connection#add/#update/#delete, though a Connection#send(AddDocument.new(...)) + # does not autocommit. Maybe #send should check for the request types that require a commit and + # commit in #send instead of the individual methods? + @autocommit = opts[:autocommit] == :on + + # Not actually opening the connection yet, just setting up the persistent connection. + @connection = Net::HTTP.new(@url.host, @url.port) + + @connection.read_timeout = opts[:timeout] if opts[:timeout] + @username = opts[:username] if opts[:username] + @password = opts[:password] if opts[:password] + end + + # add a document to the index. you can pass in either a hash + # + # conn.add(:id => 123, :title => 'Tlon, Uqbar, Orbis Tertius') + # + # or a Solr::Document + # + # conn.add(Solr::Document.new(:id => 123, :title = 'On Writing') + # + # true/false will be returned to designate success/failure + + def add(doc) + request = Solr::Request::AddDocument.new(doc) + response = send(request) + commit if @autocommit + return response.ok? + end + + # update a document in the index (really just an alias to add) + + def update(doc) + return add(doc) + end + + # performs a standard query and returns a Solr::Response::Standard + # + # response = conn.query('borges') + # + # alternative you can pass in a block and iterate over hits + # + # conn.query('borges') do |hit| + # puts hit + # end + # + # options include: + # + # :sort, :default_field, :rows, :filter_queries, :debug_query, + # :explain_other, :facets, :highlighting, :mlt, + # :operator => :or / :and + # :start => defaults to 0 + # :field_list => array, defaults to ["*", "score"] + + def query(query, options={}, &action) + # TODO: Shouldn't this return an exception if the Solr status is not ok? (rather than true/false). + create_and_send_query(Solr::Request::Standard, options.update(:query => query), &action) + end + + # performs a dismax search and returns a Solr::Response::Standard + # + # response = conn.search('borges') + # + # options are same as query, but also include: + # + # :tie_breaker, :query_fields, :minimum_match, :phrase_fields, + # :phrase_slop, :boost_query, :boost_functions + + def search(query, options={}, &action) + create_and_send_query(Solr::Request::Dismax, options.update(:query => query), &action) + end + + # sends a commit message to the server + def commit(options={}) + response = send(Solr::Request::Commit.new(options)) + return response.ok? + end + + # sends an optimize message to the server + def optimize + response = send(Solr::Request::Optimize.new) + return response.ok? + end + + # pings the connection and returns true/false if it is alive or not + def ping + begin + response = send(Solr::Request::Ping.new) + return response.ok? + rescue + return false + end + end + + # delete a document from the index using the document id + def delete(document_id) + response = send(Solr::Request::Delete.new(:id => document_id)) + commit if @autocommit + response.ok? + end + + # delete using a query + def delete_by_query(query) + response = send(Solr::Request::Delete.new(:query => query)) + commit if @autocommit + response.ok? + end + + def info + send(Solr::Request::IndexInfo.new) + end + + # send a given Solr::Request and return a RubyResponse or XmlResponse + # depending on the type of request + def send(request) + data = post(request) + Solr::Response::Base.make_response(request, data) + end + + # send the http post request to solr; for convenience there are shortcuts + # to some requests: add(), query(), commit(), delete() or send() + def post(request) + req = Net::HTTP::Post.new(@url.path + "/" + request.handler, + { "Content-Type" => request.content_type }) + req.basic_auth(@username, @password) if @username && @password + response = @connection.request(req, request.to_s) + + case response + when Net::HTTPSuccess then response.body + else + response.error! + end + + end + +private + + def create_and_send_query(klass, options = {}, &action) + request = klass.new(options) + response = send(request) + return response unless action + response.each {|hit| action.call(hit)} + end + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/document.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/document.rb new file mode 100644 index 0000000..3c91f4e --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/document.rb @@ -0,0 +1,75 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Document + include Enumerable + attr_accessor :boost + attr_reader :fields + + # Create a new Solr::Document, optionally passing in a hash of + # key/value pairs for the fields + # + # doc = Solr::Document.new(:creator => 'Jorge Luis Borges') + def initialize(hash={}) + @fields = [] + self << hash + end + + # Append a Solr::Field + # + # doc << Solr::Field.new(:creator => 'Jorge Luis Borges') + # + # If you are truly lazy you can simply pass in a hash: + # + # doc << {:creator => 'Jorge Luis Borges'} + def <<(fields) + case fields + when Hash + fields.each_pair do |name,value| + if value.respond_to?(:each) && !value.is_a?(String) + value.each {|v| @fields << Solr::Field.new(name => v)} + else + @fields << Solr::Field.new(name => value) + end + end + when Solr::Field + @fields << fields + else + raise "must pass in Solr::Field or Hash" + end + end + + # shorthand to allow hash lookups + # doc['name'] + def [](name) + field = @fields.find {|f| f.name == name.to_s} + return field.value if field + return nil + end + + # shorthand to assign as a hash + def []=(name,value) + @fields << Solr::Field.new(name => value) + end + + # convert the Document to a REXML::Element + def to_xml + e = Solr::XML::Element.new 'doc' + e.attributes['boost'] = @boost.to_s if @boost + @fields.each {|f| e.add_element(f.to_xml)} + return e + end + + def each(*args, &blk) + fields.each(&blk) + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/exception.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/exception.rb new file mode 100644 index 0000000..a439e67 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/exception.rb @@ -0,0 +1,13 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Exception < Exception; end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/field.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/field.rb new file mode 100644 index 0000000..f7bc8dd --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/field.rb @@ -0,0 +1,36 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Field + VALID_PARAMS = [:boost] + attr_accessor :name + attr_accessor :value + attr_accessor :boost + + # Accepts an optional :boost parameter, used to boost the relevance of a particular field. + def initialize(params) + @boost = params[:boost] + name_key = (params.keys - VALID_PARAMS).first + @name, @value = name_key.to_s, params[name_key] + # Convert any Time values into UTC/XML schema format (which Solr requires). + @value = @value.respond_to?(:utc) ? @value.utc.xmlschema : @value.to_str + end + + def to_xml + e = Solr::XML::Element.new 'field' + e.attributes['name'] = @name + e.attributes['boost'] = @boost.to_s if @boost + e.text = @value + return e + end + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer.rb new file mode 100755 index 0000000..a2cfce9 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer.rb @@ -0,0 +1,19 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Solr; module Importer; end; end +require File.expand_path("#{File.dirname(__FILE__)}/importer/mapper") +require File.expand_path("#{File.dirname(__FILE__)}/importer/array_mapper") +require File.expand_path("#{File.dirname(__FILE__)}/importer/delimited_file_source") +require File.expand_path("#{File.dirname(__FILE__)}/importer/hpricot_mapper") +require File.expand_path("#{File.dirname(__FILE__)}/importer/xpath_mapper") +require File.expand_path("#{File.dirname(__FILE__)}/importer/solr_source") \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/array_mapper.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/array_mapper.rb new file mode 100755 index 0000000..abef907 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/array_mapper.rb @@ -0,0 +1,26 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + + +class Solr::Importer::ArrayMapper < Solr::Importer::Mapper + # TODO document that initializer takes an array of Mappers [mapper1, mapper2, ... mapperN] + + # TODO: make merge conflict handling configurable. as is, the last map fields win. + def map(orig_data_array) + mapped_data = {} + orig_data_array.each_with_index do |data,i| + mapped_data.merge!(@mapping[i].map(data)) + end + mapped_data + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/delimited_file_source.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/delimited_file_source.rb new file mode 100755 index 0000000..70f226a --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/delimited_file_source.rb @@ -0,0 +1,38 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# For files with the first line containing field names +# Currently not designed for enormous files, as all lines are +# read into an array +class Solr::Importer::DelimitedFileSource + include Enumerable + + def initialize(filename, splitter=/\t/) + @filename = filename + @splitter = splitter + end + + def each + lines = IO.readlines(@filename) + headers = lines[0].split(@splitter).collect{|h| h.chomp} + + lines[1..-1].each do |line| + data = headers.zip(line.split(@splitter).collect{|s| s.chomp}) + def data.[](key) + self.assoc(key.to_s)[1] + end + + yield(data) + end + end + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/hpricot_mapper.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/hpricot_mapper.rb new file mode 100644 index 0000000..53a48e4 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/hpricot_mapper.rb @@ -0,0 +1,27 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +begin + require 'hpricot' + + class Solr::Importer::HpricotMapper < Solr::Importer::Mapper + def field_data(doc, path) + doc.search(path.to_s).collect { |e| e.inner_html } + end + end +rescue LoadError => e # If we can't load hpricot + class Solr::Importer::HpricotMapper + def initialize(mapping, options={}) + raise "Hpricot not installed." + end + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/mapper.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/mapper.rb new file mode 100755 index 0000000..55b199f --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/mapper.rb @@ -0,0 +1,51 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Importer::Mapper + def initialize(mapping, options={}) + @mapping = mapping + @options = options + end + + def field_data(orig_data, field_name) + orig_data[field_name] + end + + def mapped_field_value(orig_data, field_mapping) + case field_mapping + when String + field_mapping + when Proc + field_mapping.call(orig_data) # TODO pass in more context, like self or a function for field_data, etc + when Symbol + field_data(orig_data, @options[:stringify_symbols] ? field_mapping.to_s : field_mapping) + when Enumerable + field_mapping.collect {|orig_field_name| mapped_field_value(orig_data, orig_field_name)}.flatten + else + raise "Unknown mapping for #{field_mapping}" + end + end + + def map(orig_data) + mapped_data = {} + @mapping.each do |solr_name, field_mapping| + value = mapped_field_value(orig_data, field_mapping) + mapped_data[solr_name] = value if value + end + + mapped_data + end + + + + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/solr_source.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/solr_source.rb new file mode 100755 index 0000000..d8d57e5 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/solr_source.rb @@ -0,0 +1,41 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Importer::SolrSource + def initialize(solr_url, query, filter_queries=nil, options={}) + @connection = Solr::Connection.new(solr_url) + @query = query + @filter_queries = filter_queries + + @page_size = options[:page_size] || 1000 + @field_list = options[:field_list] || ["*"] + end + + def each + done = false + start = 0 + until done do + # request N documents from a starting point + request = Solr::Request::Standard.new(:query => @query, + :rows => @page_size, + :start => start, + :field_list => @field_list, + :filter_queries => @filter_queries) + response = @connection.send(request) + response.each do |doc| + yield doc # TODO: perhaps convert to HashWithIndifferentAccess.new(doc), so stringify_keys isn't necessary + end + done = start + @page_size >= response.total_hits + start = start + @page_size + end + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/xpath_mapper.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/xpath_mapper.rb new file mode 100755 index 0000000..772e1c3 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/importer/xpath_mapper.rb @@ -0,0 +1,35 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +begin + require 'xml/libxml' + + # For files with the first line containing field names + class Solr::Importer::XPathMapper < Solr::Importer::Mapper + def field_data(doc, xpath) + doc.find(xpath.to_s).collect do |node| + case node + when XML::Attr + node.value + when XML::Node + node.content + end + end + end + end +rescue LoadError => e # If we can't load libxml + class Solr::Importer::XPathMapper + def initialize(mapping, options={}) + raise "libxml not installed" + end + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/indexer.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/indexer.rb new file mode 100755 index 0000000..5210f05 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/indexer.rb @@ -0,0 +1,52 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Indexer + attr_reader :solr + + # TODO: document options! + def initialize(data_source, mapper_or_mapping, options={}) + solr_url = options[:solr_url] || ENV["SOLR_URL"] || "http://localhost:8983/solr" + @solr = Solr::Connection.new(solr_url, options) #TODO - these options contain the solr_url and debug keys also, so tidy up what gets passed + + @data_source = data_source + @mapper = mapper_or_mapping.is_a?(Hash) ? Solr::Importer::Mapper.new(mapper_or_mapping) : mapper_or_mapping + + @buffer_docs = options[:buffer_docs] + @debug = options[:debug] + end + + def index + buffer = [] + @data_source.each do |record| + document = @mapper.map(record) + + # TODO: check arrity of block, if 3, pass counter as 3rd argument + yield(record, document) if block_given? # TODO check return of block, if not true then don't index, or perhaps if document.empty? + + buffer << document + + if !@buffer_docs || buffer.size == @buffer_docs + add_docs(buffer) + buffer.clear + end + end + add_docs(buffer) if !buffer.empty? + + @solr.commit unless @debug + end + + def add_docs(documents) + @solr.add(documents) unless @debug + puts documents.inspect if @debug + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/request.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request.rb new file mode 100755 index 0000000..b568695 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request.rb @@ -0,0 +1,26 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Solr; module Request; end; end +require File.expand_path("#{File.dirname(__FILE__)}/request/base") +require File.expand_path("#{File.dirname(__FILE__)}/request/update") +require File.expand_path("#{File.dirname(__FILE__)}/request/add_document") +require File.expand_path("#{File.dirname(__FILE__)}/request/modify_document") +require File.expand_path("#{File.dirname(__FILE__)}/request/commit") +require File.expand_path("#{File.dirname(__FILE__)}/request/delete") +require File.expand_path("#{File.dirname(__FILE__)}/request/ping") +require File.expand_path("#{File.dirname(__FILE__)}/request/select") +require File.expand_path("#{File.dirname(__FILE__)}/request/standard") +require File.expand_path("#{File.dirname(__FILE__)}/request/spellcheck") +require File.expand_path("#{File.dirname(__FILE__)}/request/dismax") +require File.expand_path("#{File.dirname(__FILE__)}/request/index_info") +require File.expand_path("#{File.dirname(__FILE__)}/request/optimize") diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/add_document.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/add_document.rb new file mode 100644 index 0000000..699d2dd --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/add_document.rb @@ -0,0 +1,58 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Request::AddDocument < Solr::Request::Update + + # create the request, optionally passing in a Solr::Document + # + # request = Solr::Request::AddDocument.new doc + # + # as a short cut you can pass in a Hash instead: + # + # request = Solr::Request::AddDocument.new :creator => 'Jorge Luis Borges' + # + # or an array, to add multiple documents at the same time: + # + # request = Solr::Request::AddDocument.new([doc1, doc2, doc3]) + + def initialize(doc={}) + @docs = [] + if doc.is_a?(Array) + doc.each { |d| add_doc(d) } + else + add_doc(doc) + end + end + + # returns the request as a string suitable for posting + + def to_s + e = Solr::XML::Element.new 'add' + for doc in @docs + e.add_element doc.to_xml + end + return e.to_s + end + + private + def add_doc(doc) + case doc + when Hash + @docs << Solr::Document.new(doc) + when Solr::Document + @docs << doc + else + raise "must pass in Solr::Document or Hash" + end + end + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/base.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/base.rb new file mode 100644 index 0000000..4b65b1f --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/base.rb @@ -0,0 +1,36 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Request::Base + + + #TODO : Add base support for the debugQuery flag, and such that the response provides debug output easily + + # returns either :xml or :ruby depending on what the + # response type is for a given request + + def response_format + raise "unknown request type: #{self.class}" + end + + def content_type + 'text/xml; charset=utf-8' + end + + # returns the solr handler or url fragment that can + # respond to this type of request + + def handler + raise "unknown request type: #{self.class}" + end + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/commit.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/commit.rb new file mode 100644 index 0000000..30c43fe --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/commit.rb @@ -0,0 +1,29 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Request::Commit < Solr::Request::Update + + def initialize(options={}) + @wait_searcher = options[:wait_searcher] || true + @wait_flush = options[:wait_flush] || true + end + + + def to_s + e = Solr::XML::Element.new('commit') + e.attributes['waitSearcher'] = @wait_searcher ? 'true' : 'false' + e.attributes['waitFlush'] = @wait_flush ? 'true' : 'false' + + e.to_s + end + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/delete.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/delete.rb new file mode 100644 index 0000000..92f9067 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/delete.rb @@ -0,0 +1,48 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Request::Delete < Solr::Request::Update + + # A delete request can be for a specific document id + # + # request = Solr::Request::Delete.new(:id => 1234) + # + # or by query: + # + # request = Solr::Request::Delete.new(:query => + # + def initialize(options) + unless options.kind_of?(Hash) and (options[:id] or options[:query]) + raise Solr::Exception.new("must pass in :id or :query") + end + if options[:id] and options[:query] + raise Solr::Exception.new("can't pass in both :id and :query") + end + @document_id = options[:id] + @query = options[:query] + end + + def to_s + delete_element = Solr::XML::Element.new('delete') + if @document_id + id_element = Solr::XML::Element.new('id') + id_element.text = @document_id + delete_element.add_element(id_element) + elsif @query + query = Solr::XML::Element.new('query') + query.text = @query + delete_element.add_element(query) + end + delete_element.to_s + end +end + diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/dismax.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/dismax.rb new file mode 100644 index 0000000..13d1977 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/dismax.rb @@ -0,0 +1,46 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Request::Dismax < Solr::Request::Standard + + VALID_PARAMS.replace(VALID_PARAMS + [:tie_breaker, :query_fields, :minimum_match, :phrase_fields, :phrase_slop, + :boost_query, :boost_functions]) + + def initialize(params) + @alternate_query = params.delete(:alternate_query) + @sort_values = params.delete(:sort) + + super + + @query_type = "dismax" + end + + def to_hash + hash = super + hash[:tie] = @params[:tie_breaker] + hash[:mm] = @params[:minimum_match] + hash[:qf] = @params[:query_fields] + hash[:pf] = @params[:phrase_fields] + hash[:ps] = @params[:phrase_slop] + hash[:bq] = @params[:boost_query] + hash[:bf] = @params[:boost_functions] + hash["q.alt"] = @alternate_query + # FIXME: 2007-02-13 -- This code is duplicated in + # Solr::Request::Standard. It should be refactored into a single location. + hash[:sort] = @sort_values.collect do |sort| + key = sort.keys[0] + "#{key.to_s} #{sort[key] == :descending ? 'desc' : 'asc'}" + end.join(',') if @sort_values + return hash + end + +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/index_info.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/index_info.rb new file mode 100755 index 0000000..d4eeea5 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/index_info.rb @@ -0,0 +1,22 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Request::IndexInfo < Solr::Request::Select + + def handler + 'admin/luke' + end + + def to_hash + {:numTerms => 0}.merge(super.to_hash) + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/modify_document.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/modify_document.rb new file mode 100644 index 0000000..56e2958 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/modify_document.rb @@ -0,0 +1,46 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Request::ModifyDocument < Solr::Request::Update + + # Example: ModifyDocument.new(:id => 10, :overwrite => {:field_name => "new value"}) + def initialize(update_data) + modes = [] + @doc = {} + [:overwrite, :append, :distinct, :increment, :delete].each do |mode| + field_data = update_data[mode] + if field_data + field_data.each do |field_name, field_value| + modes << "#{field_name}:#{mode.to_s.upcase}" + @doc[field_name] = field_value if field_value # if value is nil, omit so it can be removed + end + update_data.delete mode + end + end + @mode = modes.join(",") + + # only one key should be left over, the id + @doc[update_data.keys[0].to_s] = update_data.values[0] + end + + # returns the request as a string suitable for posting + def to_s + e = Solr::XML::Element.new 'add' + e.add_element(Solr::Document.new(@doc).to_xml) + return e.to_s + end + + def handler + "update?mode=#{@mode}" + end + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/optimize.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/optimize.rb new file mode 100755 index 0000000..c6c9b45 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/optimize.rb @@ -0,0 +1,19 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Request::Optimize < Solr::Request::Update + + def to_s + Solr::XML::Element.new('optimize').to_s + end + +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/ping.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/ping.rb new file mode 100644 index 0000000..6b420be --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/ping.rb @@ -0,0 +1,36 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# TODO: Consider something lazy like this? +# Solr::Request::Ping = Solr::Request.simple_request :format=>:xml, :handler=>'admin/ping' +# class Solr::Request +# def self.simple_request(options) +# Class.new do +# def response_format +# options[:format] +# end +# def handler +# options[:handler] +# end +# end +# end +# end + +class Solr::Request::Ping < Solr::Request::Base + def response_format + :xml + end + + def handler + 'admin/ping' + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/select.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/select.rb new file mode 100644 index 0000000..c3595cc --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/select.rb @@ -0,0 +1,54 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# "Abstract" base class, only useful with subclasses that add parameters +class Solr::Request::Select < Solr::Request::Base + + attr_reader :query_type + + def initialize(qt=nil, params={}) + @query_type = qt + @select_params = params + end + + def response_format + :ruby + end + + def handler + 'select' + end + + def content_type + 'application/x-www-form-urlencoded; charset=utf-8' + end + + def to_hash + return {:qt => query_type, :wt => 'ruby'}.merge(@select_params) + end + + def to_s + raw_params = self.to_hash + + http_params = [] + raw_params.each do |key,value| + if value.respond_to? :each + value.each { |v| http_params << "#{key}=#{ERB::Util::url_encode(v)}" unless v.nil?} + else + http_params << "#{key}=#{ERB::Util::url_encode(value)}" unless value.nil? + end + end + + http_params.join("&") + end + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/spellcheck.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/spellcheck.rb new file mode 100644 index 0000000..eab24eb --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/spellcheck.rb @@ -0,0 +1,30 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Request::Spellcheck < Solr::Request::Select + + def initialize(params) + super('spellchecker') + @params = params + end + + def to_hash + hash = super + hash[:q] = @params[:query] + hash[:suggestionCount] = @params[:suggestion_count] + hash[:accuracy] = @params[:accuracy] + hash[:onlyMorePopular] = @params[:only_more_popular] + hash[:cmd] = @params[:command] + return hash + end + +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/standard.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/standard.rb new file mode 100755 index 0000000..895866f --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/standard.rb @@ -0,0 +1,409 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Request::Standard < Solr::Request::Select + + VALID_PARAMS = [:query, :sort, :default_field, :operator, :start, :rows, :shards, :date_facets, + :filter_queries, :field_list, :debug_query, :explain_other, :facets, :highlighting, :mlt, :radius, + :latitude, :longitude, :spellcheck] + + def initialize(params) + super(params[:radius].nil? ? 'standard' : 'geo') + + raise "Invalid parameters: #{(params.keys - VALID_PARAMS).join(',')}" unless + (params.keys - VALID_PARAMS).empty? + + raise ":query parameter required" unless params[:query] + + @params = params.dup + + # Validate operator + if params[:operator] + raise "Only :and/:or operators allowed" unless + [:and, :or].include?(params[:operator]) + + @params[:operator] = params[:operator].to_s.upcase + end + + # Validate start, rows can be transformed to ints + @params[:start] = params[:start].to_i if params[:start] + @params[:rows] = params[:rows].to_i if params[:rows] + + @params[:field_list] ||= ["*","score"] + + @params[:shards] ||= [] + end + + def to_hash + hash = {} + + # standard request param processing + hash[:sort] = @params[:sort] + hash[:q] = @params[:query] + hash["q.op"] = @params[:operator] + hash[:df] = @params[:default_field] + + # common parameter processing + hash[:start] = @params[:start] + hash[:rows] = @params[:rows] + hash[:fq] = @params[:filter_queries] + hash[:fl] = @params[:field_list].join(',') + hash[:debugQuery] = @params[:debug_query] + hash[:explainOther] = @params[:explain_other] + hash[:shards] = @params[:shards].join(',') unless @params[:shards].empty? + + #if @params[:qt].eql? 'geo' + hash[:radius] = @params[:radius] + hash[:lat] = @params[:latitude] + hash[:long] = @params[:longitude] + #end + + # facet parameter processing + if @params[:facets] + # TODO need validation of all that is under the :facets Hash too + hash[:facet] = true + hash["facet.field"] = [] + hash["facet.query"] = @params[:facets][:queries] + hash["facet.sort"] = @params[:facets][:sort] + hash["facet.limit"] = @params[:facets][:limit] + hash["facet.missing"] = @params[:facets][:missing] + hash["facet.mincount"] = @params[:facets][:mincount] + hash["facet.prefix"] = @params[:facets][:prefix] + hash["facet.offset"] = @params[:facets][:offset] + if @params[:facets][:fields] # facet fields are optional (could be facet.query only) + @params[:facets][:fields].each do |f| + if f.kind_of? Hash + key = f.keys[0] + value = f[key] + hash["facet.field"] << key + hash["f.#{key}.facet.sort"] = value[:sort] + hash["f.#{key}.facet.limit"] = value[:limit] + hash["f.#{key}.facet.missing"] = value[:missing] + hash["f.#{key}.facet.mincount"] = value[:mincount] + hash["f.#{key}.facet.prefix"] = value[:prefix] + hash["f.#{key}.facet.offset"] = value[:offset] + else + hash["facet.field"] << f + end + end + end + + if @params[:date_facets] + hash["facet.date"] = [] + if @params[:date_facets][:fields] + @params[:date_facets][:fields].each do |f| + if f.kind_of? Hash + key = f.keys[0] + hash["facet.date"] << key + f[key].each { |k, v| + hash["f.#{key}.facet.date.#{k}"] = v + } + else + hash["facet.date"] << f + end + end + end + hash["facet.date.start"] = @params[:date_facets][:start] + hash["facet.date.end"] = @params[:date_facets][:end] + hash["facet.date.gap"] = @params[:date_facets][:gap] + hash["facet.date.other"] = @params[:date_facets][:other] + hash["facet.date.hardend"] = @params[:date_facets][:hardend] + if @params[:date_facets][:filter] + if hash[:fq] + hash[:fq] << @params[:date_facets][:filter] + else + hash[:fq] = @params[:date_facets][:filter] + end + end + end + end + + # highlighting parameter processing - http://wiki.apache.org/solr/HighlightingParameters + if @params[:highlighting] + hash[:hl] = true + hash["hl.fl"] = @params[:highlighting][:field_list].join(',') if @params[:highlighting][:field_list] + + snippets = @params[:highlighting][:max_snippets] + if snippets + if snippets.kind_of? Hash + if snippets[:default] + hash["hl.snippets"] = snippets[:default] + end + if snippets[:fields] + snippets[:fields].each do |k,v| + hash["f.#{k}.hl.snippets"] = v + end + end + else + hash["hl.snippets"] = snippets + end + end + + fragsize = @params[:highlighting][:fragment_size] + if fragsize + if fragsize.kind_of? Hash + if fragsize[:default] + hash["hl.fragsize"] = fragsize[:default] + end + if fragsize[:fields] + fragsize[:fields].each do |k,v| + hash["f.#{k}.hl.fragsize"] = v + end + end + else + hash["hl.fragsize"] = fragsize + end + end + + rfm = @params[:highlighting][:require_field_match] + if nil != rfm + if rfm.kind_of? Hash + if nil != rfm[:default] + hash["hl.requireFieldMatch"] = rfm[:default] + end + if rfm[:fields] + rfm[:fields].each do |k,v| + hash["f.#{k}.hl.requireFieldMatch"] = v + end + end + else + hash["hl.requireFieldMatch"] = rfm + end + end + + mac = @params[:highlighting][:max_analyzed_chars] + if mac + if mac.kind_of? Hash + if mac[:default] + hash["hl.maxAnalyzedChars"] = mac[:default] + end + if mac[:fields] + mac[:fields].each do |k,v| + hash["f.#{k}.hl.maxAnalyzedChars"] = v + end + end + else + hash["hl.maxAnalyzedChars"] = mac + end + end + + prefix = @params[:highlighting][:prefix] + if prefix + if prefix.kind_of? Hash + if prefix[:default] + hash["hl.simple.pre"] = prefix[:default] + end + if prefix[:fields] + prefix[:fields].each do |k,v| + hash["f.#{k}.hl.simple.pre"] = v + end + end + else + hash["hl.simple.pre"] = prefix + end + end + + suffix = @params[:highlighting][:suffix] + if suffix + if suffix.kind_of? Hash + if suffix[:default] + hash["hl.simple.post"] = suffix[:default] + end + if suffix[:fields] + suffix[:fields].each do |k,v| + hash["f.#{k}.hl.simple.post"] = v + end + end + else + hash["hl.simple.post"] = suffix + end + end + + formatter = @params[:highlighting][:formatter] + if formatter + if formatter.kind_of? Hash + if formatter[:default] + hash["hl.formatter"] = formatter[:default] + end + if formatter[:fields] + formatter[:fields].each do |k,v| + hash["f.#{k}.hl.formatter"] = v + end + end + else + hash["hl.formatter"] = formatter + end + end + + fragmenter = @params[:highlighting][:fragmenter] + if fragmenter + if fragmenter.kind_of? Hash + if fragmenter[:default] + hash["hl.fragmenter"] = fragmenter[:default] + end + if fragmenter[:fields] + fragmenter[:fields].each do |k,v| + hash["f.#{k}.hl.fragmenter"] = v + end + end + else + hash["hl.fragmenter"] = fragmenter + end + end + + merge_contiguous = @params[:highlighting][:merge_contiguous] + if nil != merge_contiguous + if merge_contiguous.kind_of? Hash + if nil != merge_contiguous[:default] + hash["hl.mergeContiguous"] = merge_contiguous[:default] + end + if merge_contiguous[:fields] + merge_contiguous[:fields].each do |k,v| + hash["f.#{k}.hl.mergeContiguous"] = v + end + end + else + hash["hl.mergeContiguous"] = merge_contiguous + end + end + + increment = @params[:highlighting][:increment] + if increment + if increment.kind_of? Hash + if increment[:default] + hash["hl.increment"] = increment[:default] + end + if increment[:fields] + increment[:fields].each do |k,v| + hash["f.#{k}.hl.increment"] = v + end + end + else + hash["hl.increment"] = increment + end + end + + # support "old style" + alternate_fields = @params[:highlighting][:alternate_fields] + if alternate_fields + alternate_fields.each do |f,v| + hash["f.#{f}.hl.alternateField"] = v + end + end + + alternate_field = @params[:highlighting][:alternate_field] + if alternate_field + if alternate_field.kind_of? Hash + if alternate_field[:default] + hash["hl.alternateField"] = alternate_field[:default] + end + if alternate_field[:fields] + alternate_field[:fields].each do |k,v| + hash["f.#{k}.hl.alternateField"] = v + end + end + else + hash["hl.alternateField"] = alternate_field + end + end + + mafl = @params[:highlighting][:max_alternate_field_length] + if mafl + if mafl.kind_of? Hash + if mafl[:default] + hash["hl.maxAlternateFieldLength"] = mafl[:default] + end + if mafl[:fields] + mafl[:fields].each do |k,v| + hash["f.#{k}.hl.maxAlternateFieldLength"] = v + end + else + # support "old style" + mafl.each do |k,v| + hash["f.#{k}.hl.maxAlternateFieldLength"] = v + end + end + else + hash["hl.maxAlternateFieldLength"] = mafl + end + end + + hash["hl.usePhraseHighlighter"] = @params[:highlighting][:use_phrase_highlighter] + + regex = @params[:highlighting][:regex] + if regex + if regex[:slop] + if regex[:slop].kind_of? Hash + if regex[:slop][:default] + hash["hl.regex.slop"] = regex[:slop][:default] + end + if regex[:slop][:fields] + regex[:slop][:fields].each do |k,v| + hash["f.#{k}.hl.regex.slop"] = v + end + end + else + hash["hl.regex.slop"] = regex[:slop] + end + end + if regex[:pattern] + if regex[:pattern].kind_of? Hash + if regex[:pattern][:default] + hash["hl.regex.pattern"] = regex[:pattern][:default] + end + if regex[:pattern][:fields] + regex[:pattern][:fields].each do |k,v| + hash["f.#{k}.hl.regex.pattern"] = v + end + end + else + hash["hl.regex.pattern"] = regex[:pattern] + end + end + if regex[:max_analyzed_chars] + if regex[:max_analyzed_chars].kind_of? Hash + if regex[:max_analyzed_chars][:default] + hash["hl.regex.maxAnalyzedChars"] = regex[:max_analyzed_chars][:default] + end + if regex[:max_analyzed_chars][:fields] + regex[:max_analyzed_chars][:fields].each do |k,v| + hash["f.#{k}.hl.regex.maxAnalyzedChars"] = v + end + end + else + hash["hl.regex.maxAnalyzedChars"] = regex[:max_analyzed_chars] + end + end + end + + end + + if @params[:mlt] + hash[:mlt] = true + hash["mlt.count"] = @params[:mlt][:count] + hash["mlt.fl"] = @params[:mlt][:field_list].join(',') + hash["mlt.mintf"] = @params[:mlt][:min_term_freq] + hash["mlt.mindf"] = @params[:mlt][:min_doc_freq] + hash["mlt.minwl"] = @params[:mlt][:min_word_length] + hash["mlt.maxwl"] = @params[:mlt][:max_word_length] + hash["mlt.maxqt"] = @params[:mlt][:max_query_terms] + hash["mlt.maxntp"] = @params[:mlt][:max_tokens_parsed] + hash["mlt.boost"] = @params[:mlt][:boost] + end + + hash[:spellcheck] = true + hash['spellcheck.collate'] = true + + hash.merge(super.to_hash) + end + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/update.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/update.rb new file mode 100644 index 0000000..8bd8448 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/request/update.rb @@ -0,0 +1,23 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# a parent class for all requests that go through the solr update handler +# TODO: Use new xml update handler for better error responses +class Solr::Request::Update < Solr::Request::Base + def response_format + :xml + end + + def handler + 'update' + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/response.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response.rb new file mode 100755 index 0000000..9df29e6 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response.rb @@ -0,0 +1,27 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Solr; module Response; end; end +require File.expand_path("#{File.dirname(__FILE__)}/response/base") +require File.expand_path("#{File.dirname(__FILE__)}/response/xml") +require File.expand_path("#{File.dirname(__FILE__)}/response/ruby") +require File.expand_path("#{File.dirname(__FILE__)}/response/ping") +require File.expand_path("#{File.dirname(__FILE__)}/response/add_document") +require File.expand_path("#{File.dirname(__FILE__)}/response/modify_document") +require File.expand_path("#{File.dirname(__FILE__)}/response/standard") +require File.expand_path("#{File.dirname(__FILE__)}/response/spellcheck") +require File.expand_path("#{File.dirname(__FILE__)}/response/dismax") +require File.expand_path("#{File.dirname(__FILE__)}/response/commit") +require File.expand_path("#{File.dirname(__FILE__)}/response/delete") +require File.expand_path("#{File.dirname(__FILE__)}/response/index_info") +require File.expand_path("#{File.dirname(__FILE__)}/response/optimize") +require File.expand_path("#{File.dirname(__FILE__)}/response/select") \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/add_document.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/add_document.rb new file mode 100644 index 0000000..d1e1923 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/add_document.rb @@ -0,0 +1,17 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Response::AddDocument < Solr::Response::Xml + def initialize(xml) + super + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/base.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/base.rb new file mode 100644 index 0000000..a66d2a4 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/base.rb @@ -0,0 +1,42 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Response::Base + attr_reader :raw_response + + def initialize(raw_response) + @raw_response = raw_response + end + + # factory method for creating a Solr::Response::* from + # a request and the raw response content + def self.make_response(request, raw) + + # make sure response format seems sane + unless [:xml, :ruby].include?(request.response_format) + raise Solr::Exception.new("unknown response format: #{request.response_format}" ) + end + + # TODO: Factor out this case... perhaps the request object should provide the response class instead? Or dynamically align by class name? + # Maybe the request itself could have the response handling features that get mixed in with a single general purpose response object? + + begin + klass = eval(request.class.name.sub(/Request/,'Response')) + rescue NameError + raise Solr::Exception.new("unknown request type: #{request.class}") + else + klass.new(raw) + end + + end + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/commit.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/commit.rb new file mode 100644 index 0000000..3a258e6 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/commit.rb @@ -0,0 +1,15 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Response::Commit < Solr::Response::Xml +end + diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/delete.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/delete.rb new file mode 100644 index 0000000..0836128 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/delete.rb @@ -0,0 +1,13 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Response::Delete < Solr::Response::Xml; end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/dismax.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/dismax.rb new file mode 100644 index 0000000..d495843 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/dismax.rb @@ -0,0 +1,8 @@ +class Solr::Response::Dismax < Solr::Response::Standard + # no need for special processing + + # FIXME: 2007-02-07 -- The existence of this class indicates that + # the Request/Response pair architecture is a little hinky. Perhaps we could refactor + # out some of the most common functionality -- Common Query Parameters, Highlighting Parameters, + # Simple Facet Parameters, etc. -- into modules? +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/index_info.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/index_info.rb new file mode 100755 index 0000000..b8e215f --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/index_info.rb @@ -0,0 +1,26 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Response::IndexInfo < Solr::Response::Ruby + def initialize(ruby_code) + super + end + + def num_docs + return @data['index']['numDocs'] + end + + def field_names + return @data['fields'].keys + end + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/modify_document.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/modify_document.rb new file mode 100644 index 0000000..44c4f5b --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/modify_document.rb @@ -0,0 +1,17 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Response::ModifyDocument < Solr::Response::Xml + def initialize(xml) + super + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/optimize.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/optimize.rb new file mode 100755 index 0000000..4594d90 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/optimize.rb @@ -0,0 +1,14 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Response::Optimize < Solr::Response::Commit +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/ping.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/ping.rb new file mode 100644 index 0000000..5be1e90 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/ping.rb @@ -0,0 +1,26 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Response::Ping < Solr::Response::Xml + + def initialize(xml) + super + @ok = REXML::XPath.first(@doc, './solr/ping') ? true : false + end + + # returns true or false depending on whether the ping + # was successful or not + def ok? + @ok + end + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/ruby.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/ruby.rb new file mode 100644 index 0000000..05424c1 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/ruby.rb @@ -0,0 +1,42 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Response::Ruby < Solr::Response::Base + attr_reader :data, :header + + def initialize(ruby_code) + super + begin + #TODO: what about pulling up data/header/response to ResponseBase, + # or maybe a new middle class like SelectResponseBase since + # all Select queries return this same sort of stuff?? + # XML (&wt=xml) and Ruby (&wt=ruby) responses contain exactly the same structure. + # a goal of solrb is to make it irrelevant which gets used under the hood, + # but favor Ruby responses. + @data = eval(ruby_code) + @header = @data['responseHeader'] + raise "response should be a hash" unless @data.kind_of? Hash + raise "response header missing" unless @header.kind_of? Hash + rescue SyntaxError => e + raise Solr::Exception.new("invalid ruby code: #{e}") + end + end + + def ok? + @header['status'] == 0 + end + + def query_time + @header['QTime'] + end + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/select.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/select.rb new file mode 100644 index 0000000..8e2185d --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/select.rb @@ -0,0 +1,17 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Response::Select < Solr::Response::Ruby + def initialize(ruby_code) + super + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/spellcheck.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/spellcheck.rb new file mode 100644 index 0000000..a4842c5 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/spellcheck.rb @@ -0,0 +1,20 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Response::Spellcheck < Solr::Response::Ruby + attr_reader :suggestions + + def initialize(ruby_code) + super + @suggestions = @data['suggestions'] + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/standard.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/standard.rb new file mode 100644 index 0000000..91bf7db --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/standard.rb @@ -0,0 +1,65 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Response::Standard < Solr::Response::Ruby + FacetValue = Struct.new(:name, :value) + include Enumerable + + def initialize(ruby_code) + super + @response = @data['response'] + raise "response section missing" unless @response.kind_of? Hash + end + + def total_hits + @response['numFound'] + end + + def start + @response['start'] + end + + def hits + @response['docs'] + end + + def max_score + @response['maxScore'] + end + + # TODO: consider the use of json.nl parameter + def field_facets(field) + facets = [] + values = @data['facet_counts']['facet_fields'][field] + Solr::Util.paired_array_each(values) do |key, value| + facets << FacetValue.new(key, value) + end + + facets + end + + def highlighted(id, field) + @data['highlighting'][id.to_s][field.to_s] rescue nil + end + + def highlighting + @data['highlighting'] + end + + # supports enumeration of hits + # TODO revisit - should this iterate through *all* hits by re-requesting more? + def each + @response['docs'].each {|hit| yield hit} + end + +end + diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/xml.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/xml.rb new file mode 100644 index 0000000..1fff3ed --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/response/xml.rb @@ -0,0 +1,39 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Response::Xml < Solr::Response::Base + attr_reader :doc, :status_code, :status_message + + def initialize(xml) + super + # parse the xml + @doc = REXML::Document.new(xml) + + # look for the result code and string + # + # + # 02 + # + result = REXML::XPath.first(@doc, './response/lst[@name="responseHeader"]/int[@name="status"]') + if result + @status_code = result.text + @status_message = result.text # TODO: any need for a message? + end + rescue REXML::ParseException => e + raise Solr::Exception.new("invalid response xml: #{e}") + end + + def ok? + return @status_code == '0' + end + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/solrtasks.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/solrtasks.rb new file mode 100755 index 0000000..3a1f76a --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/solrtasks.rb @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# TODO: fill out Solr tasks: start, stop, ping, optimize, etc. + +require 'rake' +require 'rake/tasklib' + +module Solr + namespace :solr do + desc "Start Solr" + task :start do + # TODO: actually start it up! + puts "Starting..." + end + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/util.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/util.rb new file mode 100755 index 0000000..bb134ee --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/util.rb @@ -0,0 +1,32 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Solr::Util + # paired_array_each([key1,value1,key2,value2]) yields twice: + # |key1,value1| and |key2,value2| + def self.paired_array_each(a, &block) + 0.upto(a.size / 2 - 1) do |i| + n = i * 2 + yield(a[n], a[n+1]) + end + end + + # paired_array_to_hash([key1,value1,key2,value2]) => {key1 => value1, key2, value2} + def self.paired_array_to_hash(a) + Hash[*a] + end + + def self.query_parser_escape(string) + # backslash prefix everything that isn't a word character + string.gsub(/(\W)/,'\\\\\1') + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/solr/xml.rb b/vendor/plugins/acts_as_solr_reloaded/lib/solr/xml.rb new file mode 100644 index 0000000..af913d7 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/solr/xml.rb @@ -0,0 +1,43 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +module Solr::XML +end + +begin + + # If we can load rubygems and libxml-ruby... + require 'rubygems' + require 'xml/libxml' + raise "acts_as_solr requires libxml-ruby 0.7 or greater" unless XML::Node.public_instance_methods.collect{|x| x.to_sym}.include?(:attributes) + + # then make a few modifications to XML::Node so it can stand in for REXML::Element + class XML::Node + # element.add_element(another_element) should work + alias_method :add_element, :<< + + + # element.text = "blah" should work + def text=(x) + self << x.to_s + end + end + + # And use XML::Node for our XML generation + Solr::XML::Element = XML::Node + +rescue LoadError => e # If we can't load either rubygems or libxml-ruby + # Just use REXML. + require 'rexml/document' + Solr::XML::Element = REXML::Element + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/tasks/database.rake b/vendor/plugins/acts_as_solr_reloaded/lib/tasks/database.rake new file mode 100644 index 0000000..ea63419 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/tasks/database.rake @@ -0,0 +1,16 @@ +namespace :db do + namespace :fixtures do + desc "Load fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y" + task :load => :environment do + begin + ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => "*:*")) + ActsAsSolr::Post.execute(Solr::Request::Commit.new) + (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'test', 'fixtures', '*.{yml,csv}'))).each do |fixture_file| + ActsAsSolr::SolrFixtures.load(File.basename(fixture_file, '.*')) + end + puts "The fixtures loaded have been added to Solr" + rescue + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/tasks/solr.rake b/vendor/plugins/acts_as_solr_reloaded/lib/tasks/solr.rake new file mode 100644 index 0000000..16617a0 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/tasks/solr.rake @@ -0,0 +1,169 @@ +namespace :solr do + + desc 'Download and install Solr+Jetty 3.3.0.' + task :download do + if (File.exists?(Rails.root + '/vendor/plugins/acts_as_solr_reloaded/solr/start.jar')) + puts 'Solr already downloaded.' + else + cd '/tmp' + sh 'wget -c http://ftp.unicamp.br/pub/apache/lucene/solr/3.3.0/apache-solr-3.3.0.tgz' + sh 'tar xzf apache-solr-3.3.0.tgz' + cd 'apache-solr-3.3.0/example' + cp_r ['../LICENSE.txt', '../NOTICE.txt', 'README.txt', 'etc', 'lib', 'start.jar', 'webapps', 'work'], Rails.root + '/vendor/plugins/acts_as_solr_reloaded/solr', :verbose => true + cd 'solr' + cp_r ['README.txt', 'bin', 'solr.xml'], Rails.root + '/vendor/plugins/acts_as_solr_reloaded/solr/solr', :verbose => true + end + end + + desc 'Remove Solr instalation from the tree.' + task :remove do + solr_root = Rails.root + '/vendor/plugins/acts_as_solr_reloaded/solr/' + rm_r ['README.txt', 'bin', 'solr.xml'].map{ |i| File.join(solr_root, 'solr', i) }, :verbose => true, :force => true + rm_r ['LICENSE.txt', 'NOTICE.txt', 'README.txt', 'etc', 'lib', 'start.jar', 'webapps', 'work'].map{ |i| File.join(solr_root, i) }, :verbose => true, :force => true + end + + desc 'Update to the newest supported version of solr' + task :update => [:remove, :download] do + end + + desc 'Starts Solr. Options accepted: RAILS_ENV=your_env, PORT=XX. Defaults to development if none.' + task :start => :environment do + require File.expand_path("#{File.dirname(__FILE__)}/../../config/solr_environment") + FileUtils.mkdir_p(SOLR_LOGS_PATH) + FileUtils.mkdir_p(SOLR_DATA_PATH) + FileUtils.mkdir_p(SOLR_PIDS_PATH) + begin + n = Net::HTTP.new('127.0.0.1', SOLR_PORT) + n.request_head('/').value + + rescue Net::HTTPServerException #responding + puts "Port #{SOLR_PORT} in use" and return + + rescue Errno::ECONNREFUSED, Errno::EBADF, NoMethodError #not responding + # there's an issue with Net::HTTP.request where @socket is nil and raises a NoMethodError + # http://redmine.ruby-lang.org/issues/show/2708 + Dir.chdir(SOLR_PATH) do + cmd = "java #{SOLR_JVM_OPTIONS} -Djetty.logs=\"#{SOLR_LOGS_PATH}\" -Dsolr.solr.home=\"#{SOLR_CONFIG_PATH}\" -Dsolr.data.dir=\"#{SOLR_DATA_PATH}\" -Djetty.host=\"#{SOLR_HOST}\" -Djetty.port=#{SOLR_PORT} -jar start.jar" + puts "Executing: " + cmd + windows = RUBY_PLATFORM =~ /(win|w)32$/ + if windows + exec cmd + else + pid = fork do + STDERR.close + exec cmd + end + end + sleep(5) + File.open(SOLR_PID_FILE, "w"){ |f| f << pid} unless windows + puts "#{ENV['RAILS_ENV']} Solr started successfully on #{SOLR_HOST}:#{SOLR_PORT}, pid: #{pid}." + end + end + end + + desc 'Stops Solr. Specify the environment by using: RAILS_ENV=your_env. Defaults to development if none.' + task :stop=> :environment do + require File.expand_path("#{File.dirname(__FILE__)}/../../config/solr_environment") + fork do + if File.exists?(SOLR_PID_FILE) + File.open(SOLR_PID_FILE, "r") do |f| + pid = f.readline + Process.kill('TERM', pid.to_i) + end + File.unlink(SOLR_PID_FILE) + Rake::Task["solr:destroy_index"].invoke if ENV['RAILS_ENV'] == 'test' + puts "Solr shutdown successfully." + else + puts "PID file not found at #{SOLR_PID_FILE}. Either Solr is not running or no PID file was written." + end + end + end + + desc 'Remove Solr index' + task :destroy_index => :environment do + require File.expand_path("#{File.dirname(__FILE__)}/../../config/solr_environment") + raise "In production mode. I'm not going to delete the index, sorry." if ENV['RAILS_ENV'] == "production" + if File.exists?("#{SOLR_DATA_PATH}") + Dir["#{SOLR_DATA_PATH}/index/*"].each{|f| File.unlink(f) if File.exists?(f)} + Dir.rmdir("#{SOLR_DATA_PATH}/index") + puts "Index files removed under " + ENV['RAILS_ENV'] + " environment" + end + end + + # this task is by Henrik Nyh + # http://henrik.nyh.se/2007/06/rake-task-to-reindex-models-for-acts_as_solr + desc %{Reindexes data for all acts_as_solr models. Clears index first to get rid of orphaned records and optimizes index afterwards. RAILS_ENV=your_env to set environment. ONLY=book,person,magazine to only reindex those models; EXCEPT=book,magazine to exclude those models. START_SERVER=true to solr:start before and solr:stop after. BATCH=123 to post/commit in batches of that size: default is 300. CLEAR=false to not clear the index first; OPTIMIZE=false to not optimize the index afterwards.} + task :reindex => :environment do + require File.expand_path("#{File.dirname(__FILE__)}/../../config/solr_environment") + + includes = env_array_to_constants('ONLY') + if includes.empty? + includes = Dir.glob("#{RAILS_ROOT}/app/models/*.rb").map { |path| File.basename(path, ".rb").camelize.constantize } + end + excludes = env_array_to_constants('EXCEPT') + includes -= excludes + + optimize = env_to_bool('OPTIMIZE', true) + start_server = env_to_bool('START_SERVER', false) + clear_first = env_to_bool('CLEAR', true) + batch_size = ENV['BATCH'].to_i.nonzero? || 300 + debug_output = env_to_bool("DEBUG", false) + + RAILS_DEFAULT_LOGGER.level = ActiveSupport::BufferedLogger::INFO unless debug_output + + if start_server + puts "Starting Solr server..." + Rake::Task["solr:start"].invoke + end + + # Disable solr_optimize + module ActsAsSolr::CommonMethods + def blank() end + alias_method :deferred_solr_optimize, :solr_optimize + alias_method :solr_optimize, :blank + end + + models = includes.select { |m| m.respond_to?(:rebuild_solr_index) } + models.each do |model| + + if clear_first + puts "Clearing index for #{model}..." + ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => "#{model.solr_configuration[:type_field]}:#{model}")) + ActsAsSolr::Post.execute(Solr::Request::Commit.new) + end + + puts "Rebuilding index for #{model}..." + model.rebuild_solr_index(batch_size) + + end + + if models.empty? + puts "There were no models to reindex." + elsif optimize + puts "Optimizing..." + models.last.deferred_solr_optimize + end + + if start_server + puts "Shutting down Solr server..." + Rake::Task["solr:stop"].invoke + end + + end + + def env_array_to_constants(env) + env = ENV[env] || '' + env.split(/\s*,\s*/).map { |m| m.singularize.camelize.constantize }.uniq + end + + def env_to_bool(env, default) + env = ENV[env] || '' + case env + when /^true$/i then true + when /^false$/i then false + else default + end + end + +end + diff --git a/vendor/plugins/acts_as_solr_reloaded/lib/tasks/test.rake b/vendor/plugins/acts_as_solr_reloaded/lib/tasks/test.rake new file mode 100644 index 0000000..c1c420b --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/lib/tasks/test.rake @@ -0,0 +1,5 @@ +namespace :test do + task :migrate do + ActiveRecord::Migrator.migrate("test/db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil) + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/rails/init.rb b/vendor/plugins/acts_as_solr_reloaded/rails/init.rb new file mode 100644 index 0000000..fb35c55 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/rails/init.rb @@ -0,0 +1 @@ +require 'acts_as_solr' \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/admin-extra.html b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/admin-extra.html new file mode 100755 index 0000000..aa739da --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/admin-extra.html @@ -0,0 +1,31 @@ + + + diff --git a/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/elevate.xml b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/elevate.xml new file mode 100755 index 0000000..b91e75c --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/elevate.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + diff --git a/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/mapping-ISOLatin1Accent.txt b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/mapping-ISOLatin1Accent.txt new file mode 100755 index 0000000..c441043 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/mapping-ISOLatin1Accent.txt @@ -0,0 +1,246 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Syntax: +# "source" => "target" +# "source".length() > 0 (source cannot be empty.) +# "target".length() >= 0 (target can be empty.) + +# example: +# "À" => "A" +# "\u00C0" => "A" +# "\u00C0" => "\u0041" +# "ß" => "ss" +# "\t" => " " +# "\n" => "" + +# À => A +"\u00C0" => "A" + +# Á => A +"\u00C1" => "A" + +#  => A +"\u00C2" => "A" + +# à => A +"\u00C3" => "A" + +# Ä => A +"\u00C4" => "A" + +# Å => A +"\u00C5" => "A" + +# Æ => AE +"\u00C6" => "AE" + +# Ç => C +"\u00C7" => "C" + +# È => E +"\u00C8" => "E" + +# É => E +"\u00C9" => "E" + +# Ê => E +"\u00CA" => "E" + +# Ë => E +"\u00CB" => "E" + +# Ì => I +"\u00CC" => "I" + +# Í => I +"\u00CD" => "I" + +# Î => I +"\u00CE" => "I" + +# Ï => I +"\u00CF" => "I" + +# IJ => IJ +"\u0132" => "IJ" + +# Ð => D +"\u00D0" => "D" + +# Ñ => N +"\u00D1" => "N" + +# Ò => O +"\u00D2" => "O" + +# Ó => O +"\u00D3" => "O" + +# Ô => O +"\u00D4" => "O" + +# Õ => O +"\u00D5" => "O" + +# Ö => O +"\u00D6" => "O" + +# Ø => O +"\u00D8" => "O" + +# Œ => OE +"\u0152" => "OE" + +# Þ +"\u00DE" => "TH" + +# Ù => U +"\u00D9" => "U" + +# Ú => U +"\u00DA" => "U" + +# Û => U +"\u00DB" => "U" + +# Ü => U +"\u00DC" => "U" + +# Ý => Y +"\u00DD" => "Y" + +# Ÿ => Y +"\u0178" => "Y" + +# à => a +"\u00E0" => "a" + +# á => a +"\u00E1" => "a" + +# â => a +"\u00E2" => "a" + +# ã => a +"\u00E3" => "a" + +# ä => a +"\u00E4" => "a" + +# å => a +"\u00E5" => "a" + +# æ => ae +"\u00E6" => "ae" + +# ç => c +"\u00E7" => "c" + +# è => e +"\u00E8" => "e" + +# é => e +"\u00E9" => "e" + +# ê => e +"\u00EA" => "e" + +# ë => e +"\u00EB" => "e" + +# ì => i +"\u00EC" => "i" + +# í => i +"\u00ED" => "i" + +# î => i +"\u00EE" => "i" + +# ï => i +"\u00EF" => "i" + +# ij => ij +"\u0133" => "ij" + +# ð => d +"\u00F0" => "d" + +# ñ => n +"\u00F1" => "n" + +# ò => o +"\u00F2" => "o" + +# ó => o +"\u00F3" => "o" + +# ô => o +"\u00F4" => "o" + +# õ => o +"\u00F5" => "o" + +# ö => o +"\u00F6" => "o" + +# ø => o +"\u00F8" => "o" + +# œ => oe +"\u0153" => "oe" + +# ß => ss +"\u00DF" => "ss" + +# þ => th +"\u00FE" => "th" + +# ù => u +"\u00F9" => "u" + +# ú => u +"\u00FA" => "u" + +# û => u +"\u00FB" => "u" + +# ü => u +"\u00FC" => "u" + +# ý => y +"\u00FD" => "y" + +# ÿ => y +"\u00FF" => "y" + +# ff => ff +"\uFB00" => "ff" + +# fi => fi +"\uFB01" => "fi" + +# fl => fl +"\uFB02" => "fl" + +# ffi => ffi +"\uFB03" => "ffi" + +# ffl => ffl +"\uFB04" => "ffl" + +# ſt => ft +"\uFB05" => "ft" + +# st => st +"\uFB06" => "st" diff --git a/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/protwords.txt b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/protwords.txt new file mode 100755 index 0000000..5a32e50 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/protwords.txt @@ -0,0 +1,21 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#----------------------------------------------------------------------- +# Use a protected word file to protect against the stemmer reducing two +# unrelated words to the same base word. + +# Some non-words that normally won't be encountered, +# just to test that they won't be stemmed. +dontstems +zwhacky + diff --git a/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/schema.xml b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/schema.xml new file mode 100755 index 0000000..4f39234 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/schema.xml @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id + text + + + + + + + + + diff --git a/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/scripts.conf b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/scripts.conf new file mode 100755 index 0000000..f58b262 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/scripts.conf @@ -0,0 +1,24 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +user= +solr_hostname=localhost +solr_port=8983 +rsyncd_port=18983 +data_dir= +webapp_name=solr +master_host= +master_data_dir= +master_status_dir= diff --git a/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/solrconfig.xml b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/solrconfig.xml new file mode 100755 index 0000000..3ebd2ea --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/solrconfig.xml @@ -0,0 +1,898 @@ + + + + + + ${solr.abortOnConfigurationError:true} + + + ${solr.data.dir:./solr/data} + + + + + false + + 10 + + + + 32 + 2147483647 + 10000 + 1000 + 10000 + + + + + + + + + + + single + + + + + false + 32 + 10 + + + 2147483647 + 10000 + + + false + + + true + + + + + false + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1024 + + + + + + + + + + + + + + + + true + + + + + + + + 50 + + + 200 + + + + + + solr 0 10 + rocks 0 10 + static newSearcher warming query from solrconfig.xml + + + + + + + fast_warm 0 10 + static firstSearcher warming query from solrconfig.xml + + + + + false + + + 2 + + + + + + + + + + + + + + + + + + + + + + + explicit + map + + + + + spellcheck + + + + + + + + + + + + + dismax + explicit + 0.01 + + text^0.5 features^1.0 name^1.2 sku^1.5 id^10.0 manu^1.1 cat^1.4 + + + text^0.2 features^1.1 name^1.5 manu^1.4 manu_exact^1.9 + + + ord(popularity)^0.5 recip(rord(price),1,1000,1000)^0.3 + + + id,name,price,score + + + 2<-1 5<-2 6<90% + + 100 + *:* + + text features name + + 0 + + name + regex + + + + + + + dismax + explicit + text^0.5 features^1.0 name^1.2 sku^1.5 id^10.0 + 2<-1 5<-2 6<90% + + incubationdate_dt:[* TO NOW/DAY-1MONTH]^2.2 + + + + inStock:true + + + + cat + manu_exact + price:[* TO 500] + price:[500 TO *] + + + + + + + + + + textSpell + + + default + spell + ./spellchecker1 + true + true + + + + jarowinkler + spell + org.apache.lucene.search.spell.JaroWinklerDistance + ./spellchecker2 + + + + solr.FileBasedSpellChecker + file + spellings.txt + UTF-8 + ./spellcheckerFile + + + + + + + + false + + false + + 1 + + + spellcheck + + + + + + + + true + + + tvComponent + + + + + + + + + + + + true + + + termsComponent + + + + + + + + string + elevate.xml + + + + + + explicit + + + elevator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + standard + solrpingquery + all + + + + + + + explicit + true + + + + + + + + + 100 + + + + + + + + 70 + + 0.5 + + [-\w ,/\n\"']{20,200} + + + + + + + ]]> + ]]> + + + + + + + + + + + + + mlt + highlight + debug + + + + + + + + 5 + + + + + + + + + + solr + + + + + diff --git a/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/spellings.txt b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/spellings.txt new file mode 100755 index 0000000..44b748d --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/spellings.txt @@ -0,0 +1,2 @@ +pizza +history \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/stopwords.txt b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/stopwords.txt new file mode 100755 index 0000000..22f277f --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/stopwords.txt @@ -0,0 +1,58 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#----------------------------------------------------------------------- +# a couple of test stopwords to test that the words are really being +# configured from this file: +stopworda +stopwordb + +#Standard english stop words taken from Lucene's StopAnalyzer +a +an +and +are +as +at +be +but +by +for +if +in +into +is +it +no +not +of +on +or +s +such +t +that +the +their +then +there +these +they +this +to +was +will +with + diff --git a/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/synonyms.txt b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/synonyms.txt new file mode 100755 index 0000000..453eb31 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/synonyms.txt @@ -0,0 +1,31 @@ +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#----------------------------------------------------------------------- +#some test synonym mappings unlikely to appear in real input text +aaa => aaaa +bbb => bbbb1 bbbb2 +ccc => cccc1,cccc2 +a\=>a => b\=>b +a\,a => b\,b +fooaaa,baraaa,bazaaa + +# Some synonym groups specific to this example +GB,gib,gigabyte,gigabytes +MB,mib,megabyte,megabytes +Television, Televisions, TV, TVs +#notice we use "gib" instead of "GiB" so any WordDelimiterFilter coming +#after us won't split it into two words. + +# Synonym mappings can be used for spelling correction too +pixima => pixma + diff --git a/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/example.xsl b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/example.xsl new file mode 100755 index 0000000..6832a1d --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/example.xsl @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + <xsl:value-of select="$title"/> + + + +

+
+ This has been formatted by the sample "example.xsl" transform - + use your own XSLT to get a nicer page +
+ + + +
+ + + +
+ + + + +
+
+
+ + + + + + + + + + + + + + javascript:toggle("");? +
+ + exp + + + + + +
+ + +
+ + + + + + + +
    + +
  • +
    +
+ + +
+ + + + + + + + + + + + + + + + + + + + +
diff --git a/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/example_atom.xsl b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/example_atom.xsl new file mode 100755 index 0000000..dbc7afa --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/example_atom.xsl @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + Example Solr Atom 1.0 Feed + + This has been formatted by the sample "example_atom.xsl" transform - + use your own XSLT to get a nicer Atom feed. + + + Apache Solr + solr-user@lucene.apache.org + + + + + + tag:localhost,2007:example + + + + + + + + + <xsl:value-of select="str[@name='name']"/> + + tag:localhost,2007: + + + + + + diff --git a/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/example_rss.xsl b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/example_rss.xsl new file mode 100755 index 0000000..b5bd0cf --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/example_rss.xsl @@ -0,0 +1,66 @@ + + + + + + + + + + + + + Example Solr RSS 2.0 Feed + http://localhost:8983/solr + + This has been formatted by the sample "example_rss.xsl" transform - + use your own XSLT to get a nicer RSS feed. + + en-us + http://localhost:8983/solr + + + + + + + + + + + <xsl:value-of select="str[@name='name']"/> + + http://localhost:8983/solr/select?q=id: + + + + + + + http://localhost:8983/solr/select?q=id: + + + + diff --git a/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/luke.xsl b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/luke.xsl new file mode 100755 index 0000000..d3f71c6 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/solr/solr/conf/xslt/luke.xsl @@ -0,0 +1,337 @@ + + + + + + + + + Solr Luke Request Handler Response + + + + + + + + + <xsl:value-of select="$title"/> + + + + + +

+ +

+
+ +

Index Statistics

+ +
+ +

Field Statistics

+ + + +

Document statistics

+ + + + + + + + + + +
+ +
+ + +
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
+

+ +

+ +
+ +
+
+
+ + +
+ + 50 + 800 + 160 + blue + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ background-color: ; width: px; height: px; +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
  • + +
  • +
    +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + + + + + + + + + + + + + + + + + diff --git a/vendor/plugins/acts_as_solr_reloaded/solr_test_rakefile.rb b/vendor/plugins/acts_as_solr_reloaded/solr_test_rakefile.rb new file mode 100644 index 0000000..8f711f5 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/solr_test_rakefile.rb @@ -0,0 +1,6 @@ +require 'rubygems' +require 'rake' +dir = File.dirname(__FILE__) +$:.unshift("#{dir}/lib") +RAILS_ROOT = dir +require "acts_as_solr/tasks" diff --git a/vendor/plugins/acts_as_solr_reloaded/test/config/solr.yml b/vendor/plugins/acts_as_solr_reloaded/test/config/solr.yml new file mode 100644 index 0000000..89f6f3f --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/config/solr.yml @@ -0,0 +1,2 @@ +test: + url: http://localhost:8981/solr \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/test/db/connections/mysql/connection.rb b/vendor/plugins/acts_as_solr_reloaded/test/db/connections/mysql/connection.rb new file mode 100644 index 0000000..aef0a8c --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/db/connections/mysql/connection.rb @@ -0,0 +1,11 @@ +require 'logger' +ActiveRecord::Base.logger = Logger.new("debug.log") + +ActiveRecord::Base.establish_connection( + :adapter => "mysql", + :username => "root", + :password => "rotz2od", + :encoding => "utf8", + :database => "actsassolr_test" +) + diff --git a/vendor/plugins/acts_as_solr_reloaded/test/db/connections/sqlite/connection.rb b/vendor/plugins/acts_as_solr_reloaded/test/db/connections/sqlite/connection.rb new file mode 100644 index 0000000..b8e6348 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/db/connections/sqlite/connection.rb @@ -0,0 +1,8 @@ +require 'logger' +ActiveRecord::Base.logger = Logger.new("debug.log") + +ActiveRecord::Base.establish_connection( + :adapter => "sqlite3", + :encoding => "utf8", + :database => File.join(File.dirname(File.expand_path(__FILE__)), '..', '..', 'test.db') +) diff --git a/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/001_create_books.rb b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/001_create_books.rb new file mode 100644 index 0000000..35e4586 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/001_create_books.rb @@ -0,0 +1,15 @@ +class CreateBooks < ActiveRecord::Migration + def self.up + create_table :books, :force => true do |t| + t.column :category_id, :integer + t.column :name, :string + t.column :author, :string + t.column :type, :string + t.column :published_on, :date + end + end + + def self.down + drop_table :books + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/002_create_movies.rb b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/002_create_movies.rb new file mode 100644 index 0000000..ebd7541 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/002_create_movies.rb @@ -0,0 +1,12 @@ +class CreateMovies < ActiveRecord::Migration + def self.up + create_table :movies, :force => true do |t| + t.column :name, :string + t.column :description, :string + end + end + + def self.down + drop_table :movies + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/003_create_categories.rb b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/003_create_categories.rb new file mode 100644 index 0000000..742e3e7 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/003_create_categories.rb @@ -0,0 +1,11 @@ +class CreateCategories < ActiveRecord::Migration + def self.up + create_table :categories, :force => true do |t| + t.column :name, :string + end + end + + def self.down + drop_table :categories + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/004_create_electronics.rb b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/004_create_electronics.rb new file mode 100644 index 0000000..03ceeef --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/004_create_electronics.rb @@ -0,0 +1,16 @@ +class CreateElectronics < ActiveRecord::Migration + def self.up + create_table :electronics, :force => true do |t| + t.column :name, :string + t.column :manufacturer, :string + t.column :features, :string + t.column :category, :string + t.column :price, :string + t.timestamps + end + end + + def self.down + drop_table :electronics + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/005_create_authors.rb b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/005_create_authors.rb new file mode 100644 index 0000000..0edb4d5 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/005_create_authors.rb @@ -0,0 +1,12 @@ +class CreateAuthors < ActiveRecord::Migration + def self.up + create_table :authors, :force => true do |t| + t.column :name, :string + t.column :biography, :text + end + end + + def self.down + drop_table :authors + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/006_create_postings.rb b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/006_create_postings.rb new file mode 100644 index 0000000..4fc7863 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/006_create_postings.rb @@ -0,0 +1,9 @@ +class CreatePostings < ActiveRecord::Migration + def self.up + execute "CREATE TABLE postings(`guid` varchar(20) NOT NULL PRIMARY KEY, `name` varchar(200), `description` text)" + end + + def self.down + drop_table :postings + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/007_create_posts.rb b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/007_create_posts.rb new file mode 100644 index 0000000..03f765d --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/007_create_posts.rb @@ -0,0 +1,13 @@ +class CreatePosts < ActiveRecord::Migration + def self.up + create_table :posts, :force => true do |t| + t.column :name, :string + t.column :reply_counter, :integer + t.column :posted_at, :datetime + end + end + + def self.down + drop_table :posts + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/008_create_gadgets.rb b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/008_create_gadgets.rb new file mode 100644 index 0000000..e0acba7 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/008_create_gadgets.rb @@ -0,0 +1,11 @@ +class CreateGadgets < ActiveRecord::Migration + def self.up + create_table :gadgets, :force => true do |t| + t.column :name, :string + end + end + + def self.down + drop_table :gadgets + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/009_create_dynamic_attributes.rb b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/009_create_dynamic_attributes.rb new file mode 100644 index 0000000..0ff8f58 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/009_create_dynamic_attributes.rb @@ -0,0 +1,15 @@ +class CreateDynamicAttributes < ActiveRecord::Migration + def self.up + create_table :dynamic_attributes do |t| + t.integer :dynamicable_id + t.string :dynamicable_type + t.string :name + t.text :value + t.timestamps + end + end + + def self.down + drop_table :dynamic_attributes + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/010_create_advertises.rb b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/010_create_advertises.rb new file mode 100644 index 0000000..8e83ba2 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/010_create_advertises.rb @@ -0,0 +1,13 @@ +class CreateAdvertises < ActiveRecord::Migration + def self.up + create_table :advertises do |t| + t.column :description, :string + t.timestamps + end + end + + def self.down + drop_table :advertises + end +end + diff --git a/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/011_create_locals.rb b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/011_create_locals.rb new file mode 100644 index 0000000..1a38bd7 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/db/migrate/011_create_locals.rb @@ -0,0 +1,15 @@ +class CreateLocals < ActiveRecord::Migration + def self.up + create_table :locals do |t| + t.integer :localizable_id + t.string :localizable_type + t.string :latitude + t.string :longitude + t.timestamps + end + end + + def self.down + drop_table :locals + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/fixtures/advertises.yml b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/advertises.yml new file mode 100644 index 0000000..1bc4226 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/advertises.yml @@ -0,0 +1,12 @@ +car: + id: 1 + description: Car + +house: + id: 2 + description: House + +bike: + id: 3 + description: Bike + diff --git a/vendor/plugins/acts_as_solr_reloaded/test/fixtures/authors.yml b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/authors.yml new file mode 100644 index 0000000..c3c3571 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/authors.yml @@ -0,0 +1,9 @@ +tom_clancy: + id: 1 + name: Tom Clancy + biography: Tom Clancy (born 1947) writes novels of adventure and espionage in the international military-industrial complex that have earned him enormous popularity in the 1980s as a creator of the "techno-thriller" genre. + +stephen_king: + id: 2 + name: Stephen King + biography: Stephen King (born 1947) is a prolific and immensely popular author of horror fiction. In his works, King blends elements of the traditional gothic tale with those of the modern psychological thriller, detective, and science fiction genres. diff --git a/vendor/plugins/acts_as_solr_reloaded/test/fixtures/books.yml b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/books.yml new file mode 100644 index 0000000..50aa446 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/books.yml @@ -0,0 +1,13 @@ +splinter_cell: + id: 1 + category_id: 1 + name: Splinter Cell + author: Tom Clancy + published_on: <%= Date.today - 1.year %> + +ruby: + id: 2 + category_id: 2 + name: Ruby for Dummies + author: Peter McPeterson + published_on: <%= Date.today - 2.years %> \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/test/fixtures/categories.yml b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/categories.yml new file mode 100644 index 0000000..0d17418 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/categories.yml @@ -0,0 +1,7 @@ +thriller: + id: 1 + name: Thriller/Novels + +technical: + id: 2 + name: Technical Books \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/test/fixtures/db_definitions/mysql.sql b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/db_definitions/mysql.sql new file mode 100644 index 0000000..aac03cb --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/db_definitions/mysql.sql @@ -0,0 +1,41 @@ +DROP DATABASE IF EXISTS `actsassolr_tests`; +CREATE DATABASE IF NOT EXISTS `actsassolr_tests`; +USE `actsassolr_tests` + +CREATE TABLE `books` ( + `id` int(11) NOT NULL auto_increment, + `category_id` int(11), + `name` varchar(200) default NULL, + `author` varchar(200) default NULL, + PRIMARY KEY (`id`) +); + +CREATE TABLE `movies` ( + `id` int(11) NOT NULL auto_increment, + `name` varchar(200) default NULL, + `description` varchar(255) default NULL, + PRIMARY KEY (`id`) +); + +CREATE TABLE `categories` ( + `id` int(11) NOT NULL auto_increment, + `name` varchar(200) default NULL, + PRIMARY KEY (`id`) +); + +CREATE TABLE `electronics` ( + `id` int(11) NOT NULL auto_increment, + `name` varchar(200) default NULL, + `manufacturer` varchar(255) default NULL, + `features` varchar(255) default NULL, + `category` varchar(255) default NULL, + `price` varchar(20) default NULL, + PRIMARY KEY (`id`) +); + +CREATE TABLE `authors` ( + `id` int(11) NOT NULL auto_increment, + `name` varchar(200) default NULL, + `biography` text default NULL, + PRIMARY KEY (`id`) +); diff --git a/vendor/plugins/acts_as_solr_reloaded/test/fixtures/dynamic_attributes.yml b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/dynamic_attributes.yml new file mode 100644 index 0000000..7541237 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/dynamic_attributes.yml @@ -0,0 +1,11 @@ +DynamicAttribute: + id: 1 + #name: Description + #value: Very cool bike + #advertise_id: 1 + +DynamicAttribute: + id: 2 + #name: Price + #value: 500 + #advertise_id: 1 diff --git a/vendor/plugins/acts_as_solr_reloaded/test/fixtures/electronics.yml b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/electronics.yml new file mode 100644 index 0000000..c8df43b --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/electronics.yml @@ -0,0 +1,49 @@ +ipod_video: + id: 1 + name: Apple 60 GB Memory iPod with Video Playback Black + manufacturer: Apple Computer Inc. + features: iTunes, Podcasts, Audiobooks + category: Electronics + price: 599.00 + created_at: <%= (Time.now - 1.year).utc %> + updated_at: <%= (Time.now - 1.month).utc %> + +dell_monitor: + id: 2 + name: Dell Widescreen UltraSharp 3007WFP + manufacturer: Dell, Inc + features: 30" TFT active matrix LCD, 2560 x 1600, .25mm dot pitch, 700:1 contrast + category: Electronics + price: 750.00 + created_at: <%= (Time.now - 1.year).utc %> + updated_at: <%= (Time.now - 1.month).utc %> + +samsung_hd: + id: 3 + name: Samsung SpinPoint P120 SP2514N - hard drive - 250 GB of Memory Storage - ATA-133 + manufacturer: Samsung Electronics Co. Ltd. + features: 7200RPM, 8MB cache, IDE Ultra ATA-133 + category: Hard Drive + price: 319.00 + created_at: <%= (Time.now - 2.years).utc %> + updated_at: <%= (Time.now - 2.months).utc %> + +corsair_ram: + id: 4 + name: CORSAIR XMS 2GB (2 x 1GB) 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) Dual Channel Kit System Memory - Retail + manufacturer: Corsair Microsystems Inc. + features: CAS latency 2, 2-3-3-6 timing, 2.75v, unbuffered, heat-spreader + category: Memory + price: 155.00 + created_at: <%= (Time.now - 6.years).utc %> + updated_at: <%= (Time.now - 3.months).utc %> + +a_data_ram: + id: 5 + name: A-DATA V-Series 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - OEM + manufacturer: A-DATA Technology Inc. + features: CAS latency 3, 2.7v + category: Memory + price: 65.79 + created_at: <%= (Time.now - 9.years).utc %> + updated_at: <%= (Time.now - 4.months).utc %> diff --git a/vendor/plugins/acts_as_solr_reloaded/test/fixtures/locals.yml b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/locals.yml new file mode 100644 index 0000000..eddf888 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/locals.yml @@ -0,0 +1,9 @@ +home: + id: 1 + longitude: -77.4027 + latitude: 39.36 + +work: + id: 2 + longitude: -77.4027 + latitude: 38.36 diff --git a/vendor/plugins/acts_as_solr_reloaded/test/fixtures/movies.yml b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/movies.yml new file mode 100644 index 0000000..33cc4df --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/movies.yml @@ -0,0 +1,9 @@ +napoleon_dynamite: + id: 1 + name: Napoleon Dynamite + description: Cool movie about a goofy guy + +office_space: + id: 2 + name: Office Space + description: Hypnotized dude loves fishing but not working \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/test/fixtures/postings.yml b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/postings.yml new file mode 100644 index 0000000..834b1f2 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/fixtures/postings.yml @@ -0,0 +1,10 @@ +first: + guid: ABC-123 + name: Posting ABC + description: First posting testing primary key as string + +second: + guid: DEF-456 + name: Posting DEF + description: Second posting testing primary key as string + diff --git a/vendor/plugins/acts_as_solr_reloaded/test/functional/acts_as_solr_test.rb b/vendor/plugins/acts_as_solr_reloaded/test/functional/acts_as_solr_test.rb new file mode 100644 index 0000000..d84d4c6 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/functional/acts_as_solr_test.rb @@ -0,0 +1,501 @@ +# encoding: utf-8 +require "#{File.dirname(File.expand_path(__FILE__))}/../test_helper" + +class ActsAsSolrTest < Test::Unit::TestCase + + fixtures :books, :movies, :electronics, :postings, :authors, :advertises + + Document.destroy_all + + DynamicAttribute.delete_all + Advertise.first.dynamic_attributes.create! :name => 'Description', :value => 'A very cool bike' + Advertise.first.dynamic_attributes.create! :name => 'Price', :value => '1000' + + Local.delete_all + Local.create! :localizable => Advertise.find(1), :longitude => '-77.4027', :latitude => '39.36' + Local.create! :localizable => Advertise.find(2), :longitude => '77.4027', :latitude => '-38.36' + + # Inserting new data into Solr and making sure it's getting indexed + def test_insert_new_data + assert_equal 2, Book.count_by_solr('ruby OR splinter OR bob') + b = Book.create(:name => "Fuze in action", :author => "Bob Bobber", :category_id => 1) + assert b.valid? + assert_equal 3, Book.count_by_solr('ruby OR splinter OR bob') + end + + # Check the type column stored in the index isn't stemmed by SOLR. If it is stemmed, + # then both Post and Posting will be stored as type:Post, so a query for Posts will + # return Postings and vice versa + + def test_insert_new_data_doesnt_stem_type + assert_equal 0, Post.count_by_solr('aardvark') + p = Posting.new :name => 'aardvark', :description => "An interesting animal" + p.guid = '12AB' + p.save! + assert_equal 0, Post.count_by_solr('aardvark') + end + + def test_type_determined_from_database_if_not_explicitly_set + assert Post.configuration[:solr_fields][:posted_at][:type] == :date + end + + def test_search_includes_subclasses + Novel.create! :name => 'Wuthering Heights', :author => 'Emily Bronte' + Book.create! :name => 'Jane Eyre', :author => 'Charlotte Bronte' + assert_equal 1, Novel.find_by_solr('Bronte').total_hits + assert_equal 2, Book.find_by_solr('Bronte').total_hits + end + + # Testing basic solr search: + # Model.find_by_solr 'term' + # Note that you're able to mix free-search with fields and boolean operators + def test_find_by_solr_ruby + ['ruby', 'dummy', 'name:ruby', 'name:dummy', 'name:ruby AND author:peter', + 'author:peter AND ruby', 'peter dummy'].each do |term| + records = Book.find_by_solr term + assert_equal 1, records.total + assert_equal "Peter McPeterson", records.docs.first.author + assert_equal "Ruby for Dummies", records.docs.first.name + assert_equal ({"id" => 2, + "category_id" => 2, + "name" => "Ruby for Dummies", + "author" => "Peter McPeterson", "published_on" => (Date.today - 2.years), "type" => nil}), records.docs.first.attributes + end + end + + # Testing basic solr search: + # Model.find_by_solr 'term' + # Note that you're able to mix free-search with fields and boolean operators + def test_find_by_solr_splinter + ['splinter', 'name:splinter', 'name:splinter AND author:clancy', + 'author:clancy AND splinter', 'cell tom'].each do |term| + records = Book.find_by_solr term + assert_equal 1, records.total + assert_equal "Splinter Cell", records.docs.first.name + assert_equal "Tom Clancy", records.docs.first.author + assert_equal ({"id" => 1, "category_id" => 1, "name" => "Splinter Cell", + "author" => "Tom Clancy", "published_on" => (Date.today - 1.year), "type" => nil}), records.docs.first.attributes + end + end + + # Testing basic solr search: + # Model.find_by_solr 'term' + # Note that you're able to mix free-search with fields and boolean operators + def test_find_by_solr_ruby_or_splinter + ['ruby OR splinter', 'ruby OR author:tom', 'name:cell OR author:peter', 'dummy OR cell'].each do |term| + records = Book.find_by_solr term + assert_equal 2, records.total + end + end + + # Testing search in indexed field methods: + # + # class Movie < ActiveRecord::Base + # acts_as_solr :fields => [:name, :description, :current_time] + # + # def current_time + # Time.now.to_s + # end + # + # end + # + # The method current_time above gets indexed as being part of the + # Movie model and it's available for search as well + def test_find_with_dynamic_fields + date = Time.now.strftime('%b %d %Y') + ["dynamite AND #{date}", "description:goofy AND #{date}", "goofy napoleon #{date}", + "goofiness #{date}"].each do |term| + records = Movie.find_by_solr term + assert_equal 1, records.total + assert_equal ({"id" => 1, "name" => "Napoleon Dynamite", + "description" => "Cool movie about a goofy guy"}), records.docs.first.attributes + end + end + + # Testing basic solr search that returns just the ids instead of the objects: + # Model.find_id_by_solr 'term' + # Note that you're able to mix free-search with fields and boolean operators + def test_find_id_by_solr_ruby + ['ruby', 'dummy', 'name:ruby', 'name:dummy', 'name:ruby AND author:peter', + 'author:peter AND ruby'].each do |term| + records = Book.find_id_by_solr term + assert_equal 1, records.docs.size + assert_equal ['2'], records.docs + end + end + + # Testing basic solr search that returns just the ids instead of the objects: + # Model.find_id_by_solr 'term' + # Note that you're able to mix free-search with fields and boolean operators + def test_find_id_by_solr_splinter + ['splinter', 'name:splinter', 'name:splinter AND author:clancy', + 'author:clancy AND splinter'].each do |term| + records = Book.find_id_by_solr term + assert_equal 1, records.docs.size + assert_equal ['1'], records.docs + end + end + + # Testing basic solr search that returns just the ids instead of the objects: + # Model.find_id_by_solr 'term' + # Note that you're able to mix free-search with fields and boolean operators + def test_find_id_by_solr_ruby_or_splinter + ['ruby OR splinter', 'ruby OR author:tom', 'name:cell OR author:peter', + 'dummy OR cell'].each do |term| + records = Book.find_id_by_solr term + assert_equal 2, records.docs.size + assert_equal ['1','2'], records.docs + end + end + + # Testing basic solr search that returns the total number of records found: + # Model.find_count_by_solr 'term' + # Note that you're able to mix free-search with fields and boolean operators + def test_count_by_solr + ['ruby', 'dummy', 'name:ruby', 'name:dummy', 'name:ruby AND author:peter', + 'author:peter AND ruby'].each do |term| + assert_equal 1, Book.count_by_solr(term), "there should only be 1 result for search: #{term}" + end + end + + # Testing basic solr search that returns the total number of records found: + # Model.find_count_by_solr 'term' + # Note that you're able to mix free-search with fields and boolean operators + def test_count_by_solr_splinter + ['splinter', 'name:splinter', 'name:splinter AND author:clancy', + 'author:clancy AND splinter', 'author:clancy cell'].each do |term| + assert_equal 1, Book.count_by_solr(term) + end + end + + # Testing basic solr search that returns the total number of records found: + # Model.find_count_by_solr 'term' + # Note that you're able to mix free-search with fields and boolean operators + def test_count_by_solr_ruby_or_splinter + ['ruby OR splinter', 'ruby OR author:tom', 'name:cell OR author:peter', 'dummy OR cell'].each do |term| + assert_equal 2, Book.count_by_solr(term) + end + end + + # Testing basic solr search with additional options: + # Model.find_count_by_solr 'term', :limit => 10, :offset => 0 + def test_find_with_options + [1,2].each do |count| + records = Book.find_by_solr 'ruby OR splinter', :limit => count + assert_equal count, records.docs.size + end + end + + # Testing self.rebuild_solr_index + # - It makes sure the index is rebuilt after a data has been lost + def test_rebuild_solr_index + assert_equal 1, Book.count_by_solr('splinter') + + Book.find(:first).solr_destroy + assert_equal 0, Book.count_by_solr('splinter') + + Book.rebuild_solr_index + assert_equal 1, Book.count_by_solr('splinter') + end + + # Testing instance methods: + # - solr_save + # - solr_destroy + def test_solr_save_and_solr_destroy + assert_equal 1, Book.count_by_solr('splinter') + + Book.find(:first).solr_destroy + assert_equal 0, Book.count_by_solr('splinter') + + Book.find(:first).solr_save + assert_equal 1, Book.count_by_solr('splinter') + end + + # Testing the order of results + def test_find_returns_records_in_order + records = Book.find_by_solr 'ruby^5 OR splinter' + # we boosted ruby so ruby should come first + + assert_equal 2, records.total + assert_equal 'Ruby for Dummies', records.docs.first.name + assert_equal 'Splinter Cell', records.docs.last.name + end + + # Testing solr search with optional :order argument + def _test_with_order_option + records = Movie.find_by_solr 'office^5 OR goofiness' + assert_equal 'Hypnotized dude loves fishing but not working', records.docs.first.description + assert_equal 'Cool movie about a goofy guy', records.docs.last.description + + records = Movie.find_by_solr 'office^5 OR goofiness', :order => 'description asc' + assert_equal 'Cool movie about a goofy guy', records.docs.first.description + assert_equal 'Hypnotized dude loves fishing but not working', records.docs.last.description + end + + # Testing search with omitted :field_types should + # return the same result set as if when we use it + def test_omit_field_types_in_search + records = Electronic.find_by_solr "price:[200 TO 599.99]" + assert_match(/599/, records.docs.first.price) + assert_match(/319/, records.docs.last.price) + + records = Electronic.find_by_solr "price:[200 TO 599.99]", :order => 'price asc' + assert_match(/319/, records.docs.first.price) + assert_match(/599/, records.docs.last.price) + + end + + # Test to make sure the result returned when no matches + # are found has the same structure when there are results + def test_returns_no_matches + records = Book.find_by_solr 'rubyist' + assert_equal [], records.docs + assert_equal 0, records.total + + records = Book.find_id_by_solr 'rubyist' + assert_equal [], records.docs + assert_equal 0, records.total + + records = Book.find_by_solr 'rubyist', :facets => {} + assert_equal [], records.docs + assert_equal 0, records.total + assert_equal({"facet_fields"=>[]}, records.facets) + end + + + # Testing the :exclude_fields option when set in the + # model to make sure it doesn't get indexed + def test_exclude_fields_option + records = Electronic.find_by_solr 'audiobooks OR latency' + assert records.docs.empty? + assert_equal 0, records.total + + assert_nothing_raised{ + records = Electronic.find_by_solr 'features:audiobooks' + assert records.docs.empty? + assert_equal 0, records.total + } + end + + # Testing the :auto_commit option set to false in the model + # should not send the commit command to Solr + def test_auto_commit_turned_off + assert_equal 0, Author.count_by_solr('raymond chandler') + + original_count = Author.count + Author.create(:name => 'Raymond Chandler', :biography => 'Writes noirish detective stories') + + assert_equal original_count + 1, Author.count + assert_equal 0, Author.count_by_solr('raymond chandler') + end + + # Testing models that use a different key as the primary key + def test_search_on_model_with_string_id_field + records = Posting.find_by_solr 'first^5 OR second' + assert_equal 2, records.total + assert_equal 'ABC-123', records.docs.first.guid + assert_equal 'DEF-456', records.docs.last.guid + end + + # Making sure the result set is ordered correctly even on + # models that use a different key as the primary key + def test_records_in_order_on_model_with_string_id_field + records = Posting.find_by_solr 'first OR second^5' + assert_equal 2, records.total + assert_equal 'DEF-456', records.docs.first.guid + assert_equal 'ABC-123', records.docs.last.guid + end + + # Making sure the records are added when passing a batch size + # to rebuild_solr_index + def test_using_rebuild_solr_index_with_batch + assert_equal 2, Movie.count_by_solr('office OR napoleon') + Movie.find(:all).each(&:solr_destroy) + assert_equal 0, Movie.count_by_solr('office OR napoleon') + + Movie.rebuild_solr_index 100 + assert_equal 2, Movie.count_by_solr('office OR napoleon') + end + + # Making sure find_by_solr with scores actually return the scores + # for each individual record + def test_find_by_solr_with_score + books = Book.find_by_solr 'ruby^10 OR splinter', :scores => true + + assert_equal 2, books.total + assert (books.max_score >= 0.3 && books.max_score <= 0.6) + + books.records.each { |book| assert_not_nil book.solr_score } + assert (books.docs.first.solr_score >= 0.3 && books.docs.first.solr_score <= 0.6) + assert (books.docs.last.solr_score < books.docs.first.solr_score) + end + + # Making sure nothing breaks when html entities are inside + # the content to be indexed; and on the search as well. + def test_index_and_search_with_html_entities + description = " + inverted exclamation mark ¡ ¡ + ¤ currency ¤ ¤ + ¢ cent ¢ ¢ + £ pound £ £ + ¥ yen ¥ ¥ + ¦ broken vertical bar ¦ ¦ + § section § § + ¨ spacing diaeresis ¨ ¨ + © copyright © © + ª feminine ordinal indicator ª ª + « angle quotation mark (left) « « + ¬ negation ¬ ¬ + ­ soft hyphen ­ ­ + ® registered trademark ® ® + ™ trademark ™ ™ + ¯ spacing macron ¯ ¯ + ° degree ° ° + ± plus-or-minus ± ± + ² superscript 2 ² ² + ³ superscript 3 ³ ³ + ´ spacing acute ´ ´ + µ micro µ µ + ¶ paragraph ¶ ¶ + · middle dot · · + ¸ spacing cedilla ¸ ¸ + ¹ superscript 1 ¹ ¹ + º masculine ordinal indicator º º + » angle quotation mark (right) » » + ¼ fraction 1/4 ¼ ¼ + ½ fraction 1/2 ½ ½ + ¾ fraction 3/4 ¾ ¾ + ¿ inverted question mark ¿ ¿ + × multiplication × × + ÷ division ÷ ÷ + ♥ ♦ ♣ ♠" + + author = Author.create(:name => "Test in Action™ - Copyright © Bob", :biography => description) + assert author.valid? + author.solr_commit + + author = Author.find_by_solr 'trademark © ¾ ¡ £' + assert_equal 1, author.total + end + + def test_operator_search_option + assert_nothing_raised { + books = Movie.find_by_solr "office napoleon", :operator => :or + assert_equal 2, books.total + + books = Movie.find_by_solr "office napoleon", :operator => :and + assert_equal 0, books.total + } + + assert_raise RuntimeError do + Movie.find_by_solr "office napoleon", :operator => :bad + end + end + + # Making sure find_by_solr with scores actually return the scores + # for each individual record and orders them accordingly + def test_find_by_solr_order_by_score + books = Book.find_by_solr 'ruby^10 OR splinter', {:scores => true, :order => 'score asc' } + assert (books.docs.collect(&:solr_score).compact.size == books.docs.size), "Each book should have a score" + assert (books.docs.last.solr_score >= 0.3 && books.docs.last.solr_score <= 0.6) + + books = Book.find_by_solr 'ruby^10 OR splinter', {:scores => true, :order => 'score desc' } + assert (books.docs.first.solr_score >= 0.3 && books.docs.first.solr_score <= 0.6) + assert (books.docs.last.solr_score < books.docs.first.solr_score) + end + + # Search based on fields with the :date format + def test_indexed_date_field_format + movies = Movie.find_by_solr 'time_on_xml:[NOW-1DAY TO NOW]' + assert_equal 2, movies.total + end + + def test_query_time_is_returned + results = Book.find_by_solr('ruby') + assert_not_nil(results.query_time) + assert_equal(results.query_time.class,Fixnum) + end + + def test_should_not_index_the_record_when_offline_proc_returns_true + Gadget.search_disabled = true + gadget = Gadget.create(:name => "flipvideo mino") + assert_equal 0, Gadget.find_id_by_solr('flipvideo').total + end + + def test_should_find_filtering_a_dynamic_attribute + records = Advertise.find_by_solr "description:bike" + assert_equal 1, records.total + end + + def test_dynamic_attributes_are_faceted + records = Advertise.find_by_solr "Description:bike", :facets => { :fields => [:Description] } + expected = { "A very cool bike" => 1 } + assert_equal expected, records.facets['facet_fields']['Description_facet'] + end + + def test_search_is_an_alias_for_find_by_solr + assert_equal Advertise.find_by_solr("bike").docs, Advertise.search("bike").docs + end + + def test_search_given_a_radius + records = Advertise.search "bike", :around => {:latitude => '-39.36', + :longitude => '77.4027', + :radius => 1} + assert_equal 0, records.total + end + + def test_records_are_found_in_a_radius + records = Advertise.search "bike", :around => {:latitude => '39.36', + :longitude => '-77.4027', + :radius => 1} + assert_equal 1, records.total + end + + def test_records_are_found_with_highlight + records = Book.find_by_solr "ruby", :highlight => { :fields => "name" } + assert_equal 1, records.total + end + + def test_records_wiht_highlights_are_returned_properly + records = Book.find_by_solr "ruby", :highlight => { :fields => "name" } + expected = {"name"=>["Ruby for Dummies"]} + assert_equal expected, records.highlights.values.first + end + + def test_spellcheck + assert_equal "ruby for dummies", Book.search("rubi for dumies").suggest + end + + def test_mongo_mappers_documents_are_found + Document.new(:name => "mapper").save + assert_equal "mapper", Document.search("mapper").docs.first.name + end + + def test_total_pages_is_returned_when_limit_specified + assert_equal 2, Posting.search("test", :limit => 1).total_pages + end + + def test_total_pages_is_returned_when_limit_not_specified + assert_equal 1, Posting.search("test").total_pages + end + + def test_current_page_is_returned + assert_equal 2, Posting.search("test", :limit => 1, :offset => 1).current_page + end + + def test_current_page_1_is_returned + assert_equal 1, Posting.search("test").current_page + end + + def test_current_page_1_is_returned_when_no_records_found + assert_equal 1, Posting.search("nothing").current_page + end + + def test_page_parameter_is_accepted + assert_equal 2, Posting.search("test", :limit => 1, :page => 2).current_page + end + + def test_per_page_parameter_is_accepted + assert_equal 1, Posting.search("test", :per_page => 1).per_page + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/functional/association_indexing_test.rb b/vendor/plugins/acts_as_solr_reloaded/test/functional/association_indexing_test.rb new file mode 100644 index 0000000..c0acacf --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/functional/association_indexing_test.rb @@ -0,0 +1,37 @@ +require File.join(File.dirname(__FILE__), '../test_helper') + +class AssociationIndexingTest < Test::Unit::TestCase + + fixtures :categories, :books + + # Testing the association indexing with has_many: + # + # class Category < ActiveRecord::Base + # has_many :books + # acts_as_solr :include => [:books] + # end + # + # Note that some of the search terms below are from the 'books' + # table, but get indexed as being a part of Category + def test_search_on_fields_in_has_many_association + ['thriller', 'novel', 'splinter', 'clancy', 'tom clancy thriller'].each do |term| + assert_equal 1, Category.count_by_solr(term), "expected one result: #{term}" + end + end + + # Testing the association indexing with belongs_to: + # + # class Book < ActiveRecord::Base + # belongs_to :category + # acts_as_solr :include => [:category] + # end + # + # Note that some of the search terms below are from the 'categories' + # table, but get indexed as being a part of Book + def test_search_on_fields_in_belongs_to_association + ['splinter', 'clancy', 'tom clancy thriller', 'splinter novel'].each do |term| + assert_equal 1, Book.count_by_solr(term), "expected one result: #{term}" + end + end + +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/functional/faceted_search_test.rb b/vendor/plugins/acts_as_solr_reloaded/test/functional/faceted_search_test.rb new file mode 100644 index 0000000..582ce0a --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/functional/faceted_search_test.rb @@ -0,0 +1,163 @@ +require File.join(File.dirname(__FILE__), '../test_helper') + +class FacetedSearchTest < Test::Unit::TestCase + + fixtures :electronics + + # The tests below are for faceted search, but make sure you setup + # the fields on your model you'd like to index as a facet field: + # + # class Electronic < ActiveRecord::Base + # acts_as_solr :facets => [:category, :manufacturer] + # end + # + # A basic faceted search using just one facet field + def test_faceted_search_basic + records = Electronic.find_by_solr "memory", :facets => {:fields =>[:category]} + assert_equal 4, records.docs.size + assert_match /Apple 60 GB Memory iPod/, records.docs.first.name + assert_equal({"category_facet" => {"Electronics" => 1, + "Memory" => 2, + "Hard Drive" => 1}}, + records.facets['facet_fields']) + end + + # Making sure the empty result returned what we expected + def test_faceted_search_no_matches + records = Electronic.find_by_solr "not found", :facets => { :fields => [:category]} + assert_equal [], records.docs + assert_equal [], records.facets['facet_fields'] + end + + # A basic faceted search using multiple facet fields + def test_faceted_search_multiple_fields + records = Electronic.find_by_solr "memory", :facets => {:fields =>[:category, :manufacturer]} + assert_equal 4, records.docs.size + assert_equal({"category_facet" => {"Electronics" => 1, + "Memory" => 2, + "Hard Drive" => 1}, + "manufacturer_facet" => {"Dell, Inc" => 0, + "Samsung Electronics Co. Ltd." => 1, + "Corsair Microsystems Inc." => 1, + "A-DATA Technology Inc." => 1, + "Apple Computer Inc." => 1}}, records.facets['facet_fields']) + end + + # A basic faceted search using facet queries to get counts. + # Here are the facets search query meaning: + # "price:[* TO 200]" - Price up to 200 + # "price:[200 TO 500]" - Price from 200 to 500 + # "price:[500 TO *]" - Price higher than 500 + def test_facet_search_with_query + records = Electronic.find_by_solr "memory", :facets => {:query => ["price:[* TO 200.00]", + "price:[200.00 TO 500.00]", + "price:[500.00 TO *]"]} + assert_equal 4, records.docs.size + assert_equal({"facet_queries" => {"price_rf:[* TO 200.00]"=>2, + "price_rf:[200.00 TO 500.00]"=>1, + "price_rf:[500.00 TO *]"=>1}, + "facet_fields" => {}, "facet_dates" => {}}, records.facets) + end + + # Faceted search specifying the query and fields + def test_facet_search_with_query_and_field + records = Electronic.find_by_solr "memory", :facets => {:query => ["price:[* TO 200.00]", + "price:[200.00 TO 500.00]", + "price:[500.00 TO *]"], + :fields => [:category, :manufacturer]} + + q = records.facets["facet_queries"] + assert_equal 2, q["price_rf:[* TO 200.00]"] + assert_equal 1, q["price_rf:[500.00 TO *]"] + assert_equal 1, q["price_rf:[200.00 TO 500.00]"] + + f = records.facets["facet_fields"] + assert_equal 1, f["category_facet"]["Electronics"] + assert_equal 2, f["category_facet"]["Memory"] + assert_equal 1, f["category_facet"]["Hard Drive"] + assert_equal 1, f["manufacturer_facet"]["Samsung Electronics Co. Ltd."] + assert_equal 1, f["manufacturer_facet"]["Corsair Microsystems Inc."] + assert_equal 1, f["manufacturer_facet"]["A-DATA Technology Inc."] + assert_equal 1, f["manufacturer_facet"]["Apple Computer Inc."] + end + + # Faceted searches with :sort and :zeros options turned on/off + def test_faceted_search_using_zero_and_sort + records = Electronic.find_by_solr "memory", :facets => {:fields =>[:category]} + assert_equal({"category_facet"=>{"Electronics"=>1, "Memory"=>2, "Hard Drive"=>1}}, records.facets['facet_fields']) + + records = Electronic.find_by_solr "memory", :facets => {:sort => true, :fields =>[:category]} + assert_equal({"category_facet"=>{"Memory"=>2, "Electronics"=>1, "Hard Drive"=>1}}, records.facets['facet_fields']) + + records = Electronic.find_by_solr "memory", :facets => {:fields =>[:manufacturer]} + assert_equal({"manufacturer_facet" => {"Dell, Inc" => 0, + "Samsung Electronics Co. Ltd." => 1, + "Corsair Microsystems Inc." => 1, + "A-DATA Technology Inc." => 1, + "Apple Computer Inc." => 1}}, records.facets['facet_fields']) + + records = Electronic.find_by_solr "memory", :facets => {:zeros => false, :fields =>[:manufacturer]} + assert_equal({"manufacturer_facet" => {"Samsung Electronics Co. Ltd." => 1, + "Corsair Microsystems Inc." => 1, + "A-DATA Technology Inc." => 1, + "Apple Computer Inc." => 1}}, records.facets['facet_fields']) + end + + # Faceted search with 'drill-down' option being passed. + # The :browse option receives the argument in the format: + # "facet_field:term". You can drill-down to as many + # facet fields as you like + def test_faceted_search_with_drill_down + records = Electronic.find_by_solr "memory", :facets => {:fields =>[:category]} + assert_equal 4, records.docs.size + assert_equal({"category_facet"=>{"Electronics"=>1, "Memory"=>2, "Hard Drive"=>1}}, records.facets['facet_fields']) + + records = Electronic.find_by_solr "memory", :facets => {:fields =>[:category], + :browse => "category:Memory", + :zeros => false} + assert_equal 2, records.docs.size + assert_equal({"category_facet"=>{"Memory"=>2}}, records.facets['facet_fields']) + end + + def test_faceted_search_with_dates + records = Electronic.find_by_solr "memory", :facets => {:dates => {:fields => [:created_at, :updated_at], + :start => (Date.today - 7.years).strftime("%Y-%m-%dT%H:%M:%SZ"), :end => Date.today.strftime("%Y-%m-%dT%H:%M:%SZ"), :gap => '+1YEAR', :other => :all}} + + assert_equal 4, records.docs.size + + assert_equal 0, records.facets["facet_dates"]["created_at_d"]["after"] + assert_equal 1, records.facets["facet_dates"]["created_at_d"]["before"] + assert_equal 3, records.facets["facet_dates"]["created_at_d"]["between"] + + assert_equal 0, records.facets["facet_dates"]["updated_at_d"]["after"] + assert_equal 0, records.facets["facet_dates"]["updated_at_d"]["before"] + assert_equal 4, records.facets["facet_dates"]["updated_at_d"]["between"] + end + + def test_faceted_search_with_dates_filter + records = Electronic.find_by_solr "memory", :facets => {:dates => {:filter => ["updated_at:[#{(Date.today - 3.months).strftime("%Y-%m-%dT%H:%M:%SZ")} TO NOW-1MONTH/DAY]"]}} + + assert_equal 2, records.docs.size + + records.docs.each { |r| + assert r.updated_at >= (Date.today - 3.month) + assert r.updated_at <= (Date.today - 1.month) + } + end + + def test_faceted_search_with_dates_filter_and_facets + # this is a very contrived example but gives us data to validate + records = Electronic.find_by_solr "memory", :facets => {:dates => {:filter => ["updated_at:[#{(Date.today - 3.months).strftime("%Y-%m-%dT%H:%M:%SZ")} TO NOW-1MONTH/DAY]"], + :fields => [:created_at, :updated_at], :start => 'NOW-2MONTHS/DAY', :end => 'NOW-1MONTH/DAY', :gap => '+1MONTH', :other => :all}} + + assert_equal 2, records.docs.size + + assert_equal 0, records.facets["facet_dates"]["created_at_d"]["after"] + assert_equal 2, records.facets["facet_dates"]["created_at_d"]["before"] + assert_equal 0, records.facets["facet_dates"]["created_at_d"]["between"] + + assert_equal 0, records.facets["facet_dates"]["updated_at_d"]["after"] + assert_equal 1, records.facets["facet_dates"]["updated_at_d"]["before"] + assert_equal 1, records.facets["facet_dates"]["updated_at_d"]["between"] + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/functional/multi_solr_search_test.rb b/vendor/plugins/acts_as_solr_reloaded/test/functional/multi_solr_search_test.rb new file mode 100644 index 0000000..4c500c0 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/functional/multi_solr_search_test.rb @@ -0,0 +1,57 @@ +require File.join(File.dirname(__FILE__), '../test_helper') + +class ActsAsSolrTest < Test::Unit::TestCase + + fixtures :books, :movies + + # Testing the multi_solr_search with the returning results being objects + def test_multi_solr_search_return_objects + records = Book.multi_solr_search "Napoleon OR Tom", :models => [Movie], :results_format => :objects + assert_equal 2, records.total + classes = records.docs.map {|d| d.class} + assert classes.include?(Book) + assert classes.include?(Movie) + end + + # Testing the multi_solr_search with the returning results being ids + def test_multi_solr_search_return_ids + records = Book.multi_solr_search "Napoleon OR Tom", :models => [Movie], :results_format => :ids + assert_equal 2, records.total + assert records.docs.include?({"id" => "Movie:1"}) + assert records.docs.include?({"id" => "Book:1"}) + end + + # Testing the multi_solr_search with multiple models + def test_multi_solr_search_multiple_models + # TODO: Generalize me + ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => 'type_s:Author AND NOT id:"Author:1" AND NOT id:"Author:2"')) + ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => 'type_s:Book AND NOT id:"Book:1" AND NOT id:"Book:2"')) + ActsAsSolr::Post.execute(Solr::Request::Commit.new) + + records = Book.multi_solr_search "Napoleon OR Tom OR Thriller", :models => [Movie, Category], :results_format => :ids + assert_equal 3, records.total + assert records.docs.include?({"id" => "Category:1"}) + assert records.docs.include?({"id" =>"Book:1"}) + assert records.docs.include?({"id" => "Movie:1"}) + end + + # Testing empty result set format + def test_returns_no_matches + records = Book.multi_solr_search "not found", :models => [Movie, Category] + assert_equal [], records.docs + assert_equal 0, records.total + end + + def test_search_on_empty_string_does_not_return_nil + records = Book.multi_solr_search('', :models => [Movie, Category]) + assert_not_nil records + assert_equal [], records.docs + assert_equal 0, records.total + end + + def test_search_with_score_should_set_score + records = Book.multi_solr_search "Napoleon OR Tom", :models => [Movie], :results_format => :objects, :scores => true + assert records.docs.first.solr_score.is_a?(Float) + assert records.docs.last.solr_score.is_a?(Float) + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/models/advertise.rb b/vendor/plugins/acts_as_solr_reloaded/test/models/advertise.rb new file mode 100644 index 0000000..1bbc326 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/models/advertise.rb @@ -0,0 +1,6 @@ +# Table fields for 'advertises' +# - id + +class Advertise < ActiveRecord::Base + acts_as_solr :dynamic_attributes => true, :spatial => true +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/models/author.rb b/vendor/plugins/acts_as_solr_reloaded/test/models/author.rb new file mode 100644 index 0000000..6ce9180 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/models/author.rb @@ -0,0 +1,10 @@ +# Table fields for 'movies' +# - id +# - name +# - biography + +class Author < ActiveRecord::Base + + acts_as_solr :auto_commit => false + +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/test/models/book.rb b/vendor/plugins/acts_as_solr_reloaded/test/models/book.rb new file mode 100644 index 0000000..18c416d --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/models/book.rb @@ -0,0 +1,10 @@ +# Table fields for 'books' +# - id +# - category_id +# - name +# - author + +class Book < ActiveRecord::Base + belongs_to :category + acts_as_solr :include => [:category] +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/test/models/category.rb b/vendor/plugins/acts_as_solr_reloaded/test/models/category.rb new file mode 100644 index 0000000..09e2fa4 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/models/category.rb @@ -0,0 +1,8 @@ +# Table fields for 'categories' +# - id +# - name + +class Category < ActiveRecord::Base + has_many :books + acts_as_solr :include => [:books] +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/test/models/document.rb b/vendor/plugins/acts_as_solr_reloaded/test/models/document.rb new file mode 100644 index 0000000..4ce56ef --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/models/document.rb @@ -0,0 +1,6 @@ +class Document + include MongoMapper::Document + include ActsAsSolr::MongoMapper + key :name, String + acts_as_solr +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/test/models/dynamic_attribute.rb b/vendor/plugins/acts_as_solr_reloaded/test/models/dynamic_attribute.rb new file mode 100644 index 0000000..ebc59db --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/models/dynamic_attribute.rb @@ -0,0 +1,7 @@ +# Table fields for 'dynamic attributes' +# - id +# - name +# - value + +class DynamicAttribute < ActiveRecord::Base +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/models/electronic.rb b/vendor/plugins/acts_as_solr_reloaded/test/models/electronic.rb new file mode 100644 index 0000000..52f25f2 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/models/electronic.rb @@ -0,0 +1,25 @@ +# Table fields for 'electronics' +# - id +# - name +# - manufacturer +# - features +# - category +# - price +# - created_on + +class Electronic < ActiveRecord::Base + acts_as_solr do + { + :facets => [:category, :manufacturer], + :fields => [:name, :manufacturer, :features, :category, {:created_at => :date}, {:updated_at => :date}, {:price => {:type => :range_float, :boost => 10.0}}], + :boost => 5.0, + :exclude_fields => [:features] + } + end + + # The following example would also convert the :price field type to :range_float + # + # acts_as_solr :facets => [:category, :manufacturer], + # :fields => [:name, :manufacturer, :features, :category, {:price => :range_float}], + # :boost => 5.0 +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/models/gadget.rb b/vendor/plugins/acts_as_solr_reloaded/test/models/gadget.rb new file mode 100644 index 0000000..4782176 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/models/gadget.rb @@ -0,0 +1,9 @@ +class Gadget < ActiveRecord::Base + cattr_accessor :search_disabled + + acts_as_solr :offline => proc {|record| Gadget.search_disabled?}, :format => :ids + + def self.search_disabled? + search_disabled + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/test/models/local.rb b/vendor/plugins/acts_as_solr_reloaded/test/models/local.rb new file mode 100644 index 0000000..e2964cc --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/models/local.rb @@ -0,0 +1,7 @@ +# Table fields for 'movies' +# - id +# - longitude +# - latitude + +class Local < ActiveRecord::Base +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/models/movie.rb b/vendor/plugins/acts_as_solr_reloaded/test/models/movie.rb new file mode 100644 index 0000000..e1d4dab --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/models/movie.rb @@ -0,0 +1,17 @@ +# Table fields for 'movies' +# - id +# - name +# - description + +class Movie < ActiveRecord::Base + acts_as_solr :additional_fields => [:current_time, {:time_on_xml => :date}] + + def current_time + Time.now.to_s + end + + def time_on_xml + Time.now + end + +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/test/models/novel.rb b/vendor/plugins/acts_as_solr_reloaded/test/models/novel.rb new file mode 100644 index 0000000..09fad52 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/models/novel.rb @@ -0,0 +1,2 @@ +class Novel < Book +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/test/models/post.rb b/vendor/plugins/acts_as_solr_reloaded/test/models/post.rb new file mode 100644 index 0000000..4388aaa --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/models/post.rb @@ -0,0 +1,3 @@ +class Post < ActiveRecord::Base + acts_as_solr +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/test/models/posting.rb b/vendor/plugins/acts_as_solr_reloaded/test/models/posting.rb new file mode 100644 index 0000000..f71070a --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/models/posting.rb @@ -0,0 +1,11 @@ +# Table fields for 'movies' +# - guid +# - name +# - description + +class Posting < ActiveRecord::Base + + set_primary_key 'guid' + acts_as_solr({},{:primary_key_field => 'pk_s'}) + +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/test/test_helper.rb b/vendor/plugins/acts_as_solr_reloaded/test/test_helper.rb new file mode 100644 index 0000000..f23e987 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/test_helper.rb @@ -0,0 +1,70 @@ +require 'rubygems' +require 'test/unit' +require 'active_record' +require 'active_record/fixtures' + +require 'ruby-debug' + +begin + require 'active_support/test_case' +rescue +end + +require 'mongo_mapper' + +MongoMapper.database = "acts_as_solr_reloaded-test" + +RAILS_ROOT = File.dirname(__FILE__) unless defined? RAILS_ROOT +RAILS_ENV = 'test' unless defined? RAILS_ENV +ENV["RAILS_ENV"] = "test" +ENV["ACTS_AS_SOLR_TEST"] = "true" + +require File.expand_path(File.dirname(__FILE__) + '/../lib/acts_as_solr') +require File.expand_path(File.dirname(__FILE__) + '/../config/solr_environment.rb') + +# Load Models +models_dir = File.join(File.dirname( __FILE__ ), 'models') +require "#{models_dir}/book.rb" +Dir[ models_dir + '/*.rb'].each { |m| require m } + +if defined?(ActiveSupport::TestCase) + class ActiveSupport::TestCase + include ActiveRecord::TestFixtures + self.fixture_path = File.dirname(__FILE__) + "/fixtures/" + end unless ActiveSupport::TestCase.respond_to?(:fixture_path=) +else + Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/" +end + +class Test::Unit::TestCase + def self.fixtures(*table_names) + fixture_path = defined?(ActiveSupport::TestCase) ? ActiveSupport::TestCase.fixture_path : Test::Unit::TestCase.fixture_path + if block_given? + Fixtures.create_fixtures(fixture_path, table_names) { yield } + else + Fixtures.create_fixtures(fixture_path, table_names) + end + table_names.each do |table_name| + clear_from_solr(table_name) + klass = instance_eval table_name.to_s.capitalize.singularize + klass.find(:all).each{|content| content.solr_save} + end + + clear_from_solr(:novels) + end + + private + def self.clear_from_solr(table_name) + ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => "type_s:#{table_name.to_s.capitalize.singularize}")) + end +end + +class Rails + def self.root + RAILS_ROOT + end + + def self.env + RAILS_ENV + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/unit/acts_methods_shoulda.rb b/vendor/plugins/acts_as_solr_reloaded/test/unit/acts_methods_shoulda.rb new file mode 100644 index 0000000..0dfd5e9 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/unit/acts_methods_shoulda.rb @@ -0,0 +1,110 @@ +require File.expand_path("#{File.dirname(__FILE__)}/test_helper") + +class ActsMethodsTest < Test::Unit::TestCase + class Model + attr_accessor :birthdate + + def initialize(birthdate) + @birthdate = birthdate + end + + def self.configuration + @configuration ||= {:solr_fields => {}} + end + + def self.columns_hash=(columns_hash) + @columns_hash = columns_hash + end + + def self.columns_hash + @columns_hash + end + + def [](key) + @birthday + end + + self.extend ActsAsSolr::ActsMethods + end + + class Abstract + def self.acts_as_taggable_on(what) + @_taggable = what.eql?(:tags) + end + + def self.taggable? + @_taggable + end + extend ActsAsSolr::ActsMethods + end + + class Taggable < Abstract + begin + acts_as_solr :taggable => true + rescue + end + end + + class NotTaggable < Abstract + end + + class Mapper + include MongoMapper::Document + include ActsAsSolr::MongoMapper + key :value1, String + acts_as_solr + end + + should "define the model as taggable if taggable is true" do + assert Taggable.taggable? + end + + should "not define the model as taggable if taggable is not true" do + assert !NotTaggable.taggable? + end + + should "define the type of a MongoMapper document id as text" do + assert_equal :text, Mapper.configuration[:solr_fields][:_id][:type] + end + + should "recognize the type String of a MongoMapper key as text" do + assert_equal :text, Mapper.configuration[:solr_fields][:value1][:type] + end + + context "when getting field values" do + setup do + Model.columns_hash = {"birthdate" => stub("column", :type => :date)} + Model.send(:get_field_value, :birthdate) + end + + should "define an accessor methods for a solr converted value" do + assert Model.instance_methods.include?("birthdate_for_solr") + end + + context "for date types" do + setup do + @model = Model.new(Date.today) + end + + should "return nil when field is nil" do + @model.birthdate = nil + assert_nil @model.birthdate_for_solr + end + + should "return the formatted date" do + assert_equal Date.today.strftime("%Y-%m-%dT%H:%M:%SZ"), @model.birthdate_for_solr + end + end + + context "for timestamp types" do + setup do + @now = Time.now + @model = Model.new(@now) + end + + should "return a formatted timestamp string for timestamps" do + assert_equal @now.utc.strftime("%Y-%m-%dT%H:%M:%SZ"), @model.birthdate_for_solr + end + end + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/unit/class_methods_shoulda.rb b/vendor/plugins/acts_as_solr_reloaded/test/unit/class_methods_shoulda.rb new file mode 100644 index 0000000..7235d55 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/unit/class_methods_shoulda.rb @@ -0,0 +1,85 @@ +require File.expand_path("#{File.dirname(__FILE__)}/test_helper") + +class User + attr_accessor :name, :id + def self.find(*args) + @paul ||= User.new + @paul.name = "Paul" + @paul.id = 1 + @paul + end + + def self.find_by_id(id) + find + end + + def self.primary_key + "id" + end +end + +class ClassMethodsTest < Test::Unit::TestCase + include ActsAsSolr::ClassMethods + + def solr_configuration + @solr_configuration ||= {:type_field => "type_t", :primary_key_field => "id"} + end + + context "when multi-searching" do + setup do + stubs(:name).returns("User") + end + + should "include the type field in the query" do + expects(:parse_query).with("name:paul", {:results_format => :objects}, "AND (type_t:User)") + multi_solr_search("name:paul") + end + + should "add all models in the query" do + expects(:parse_query).with("name:paul", {:results_format => :objects, :models => ["Movie", "DVD"]}, "AND (type_t:User OR type_t:Movie OR type_t:DVD)") + multi_solr_search("name:paul", :models => ["Movie", "DVD"]) + end + + should "return an empty result set if no data was returned" do + stubs(:parse_query).returns(nil) + result = multi_solr_search("name:paul") + assert_equal 0, result.docs.size + end + + should "return an empty result set if no results were found" do + stubs(:parse_query).returns(stub(:total_hits => 0, :hits => [])) + result = multi_solr_search("name:paul") + assert_equal 0, result.docs.size + end + + context "with results" do + should "find the objects in the database" do + stubs(:parse_query).returns(stub(:total_hits => 1, :hits => ["score" => 0.12956427, "id" => ["User:1"]])) + result = multi_solr_search("name:paul") + + assert_equal(User.find, result.docs.first) + assert_equal 1, result.docs.size + end + + context "when requesting ids" do + should "return only ids" do + stubs(:parse_query).returns(stub(:total_hits => 1, :hits => ["score" => 0.12956427, "id" => ["User:1"]])) + result = multi_solr_search("name:paul", :results_format => :ids) + assert_equal "User:1", result.docs.first["id"] + end + end + + context "with scores" do + setup do + solr_configuration[:primary_key_field] = nil + end + + should "add an accessor with the solr score" do + stubs(:parse_query).returns(stub(:total_hits => 1, :hits => ["score" => 0.12956427, "id" => ["User:1"]])) + result = multi_solr_search("name:paul", :scores => true) + assert_equal 0.12956427, result.docs.first.solr_score + end + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/test/unit/common_methods_shoulda.rb b/vendor/plugins/acts_as_solr_reloaded/test/unit/common_methods_shoulda.rb new file mode 100644 index 0000000..fd70ed3 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/unit/common_methods_shoulda.rb @@ -0,0 +1,128 @@ +require File.expand_path("#{File.dirname(__FILE__)}/test_helper") + +class CommonMethodsTest < Test::Unit::TestCase + include ActsAsSolr::CommonMethods + + class Mongo + include MongoMapper::Document + include ActsAsSolr::MongoMapper + acts_as_solr + + def id + '4b5e0119f3a4b02902000001' + end + end + + class << self + def primary_key + "id" + end + end + + def id + 10 + end + + context "when determining the field type" do + setup do + end + + should "return i for an integer" do + assert_equal "i", get_solr_field_type(:integer) + end + + should "return f for a float" do + assert_equal "f", get_solr_field_type(:float) + end + + should "return b for a boolean" do + assert_equal "b", get_solr_field_type(:boolean) + end + + should "return s for a string" do + assert_equal "s", get_solr_field_type(:string) + end + + should "return t for a text" do + assert_equal "t", get_solr_field_type(:text) + end + + should "return d for a date" do + assert_equal "d", get_solr_field_type(:date) + end + + should "return ri for a range_integer" do + assert_equal "ri", get_solr_field_type(:range_integer) + end + + should "return rf for a range_float" do + assert_equal "rf", get_solr_field_type(:range_float) + end + + should "return facet for a facet field" do + assert_equal "facet", get_solr_field_type(:facet) + end + + should "return the string if one was given as an argument" do + assert_equal "string", get_solr_field_type("string") + end + + should "raise an error if invalid field type was specified" do + assert_raise(RuntimeError) {get_solr_field_type(:something)} + end + + should "raise an error if argument is not symbol or string" do + assert_raise(RuntimeError) {get_solr_field_type(123)} + end + end + + context "when determining a default value for a field when it's nil" do + should "return 0.00 for a float" do + assert_equal 0.00, set_value_if_nil("f") + assert_equal 0.00, set_value_if_nil(:float) + assert_equal 0.00, set_value_if_nil("rf") + assert_equal 0.00, set_value_if_nil(:range_float) + end + + should "return 0 for an integer" do + assert_equal 0, set_value_if_nil(:integer) + assert_equal 0, set_value_if_nil(:range_integer) + assert_equal 0, set_value_if_nil("i") + assert_equal 0, set_value_if_nil("ri") + end + + should "return false for a boolean" do + assert_equal "false", set_value_if_nil(:boolean) + assert_equal "false", set_value_if_nil("b") + end + + should "return empty string for strings and text" do + assert_equal "", set_value_if_nil(:string) + assert_equal "", set_value_if_nil(:text) + assert_equal "", set_value_if_nil("t") + assert_equal "", set_value_if_nil("s") + end + + should "return an empty string for a date" do + assert_equal "", set_value_if_nil(:date) + assert_equal "", set_value_if_nil("d") + end + + should "return an empty string for everything else" do + assert_equal "", set_value_if_nil("something") + end + end + + context "when determining the record id" do + context "on ActiveRecord" do + should "return the primary key value" do + assert_equal 10, record_id(self) + end + end + context "on MongoMapper" do + should "return the id value" do + assert_equal '4b5e0119f3a4b02902000001', record_id(Mongo.new) + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/test/unit/instance_methods_shoulda.rb b/vendor/plugins/acts_as_solr_reloaded/test/unit/instance_methods_shoulda.rb new file mode 100644 index 0000000..a1c7f5b --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/unit/instance_methods_shoulda.rb @@ -0,0 +1,372 @@ +require File.expand_path("#{File.dirname(__FILE__)}/test_helper") +module Solr; end + +class InstanceMethodsTest < Test::Unit::TestCase + + context "With a Solr record instance" do + setup do + @instance = SolrInstance.new + end + + context "when checking whether indexing is disabled" do + + setup do + @instance.configuration = {:if => true} + end + + should "return true if the specified proc returns true " do + @instance.configuration[:offline] = proc {|record| true} + assert @instance.indexing_disabled? + end + + should "return false if the specified proc returns false" do + @instance.configuration[:offline] = proc {|record| false} + assert !@instance.indexing_disabled? + end + + should "return true if no valid offline option was specified" do + @instance.configuration[:offline] = nil + @instance.configuration[:if] = proc {true} + assert !@instance.indexing_disabled? + end + end + + context "when validating the boost" do + setup do + @instance.solr_configuration = {:default_boost => 10.0} + @instance.configuration = {:if => true} + end + + should "accept and evaluate a block" do + @instance.configuration[:boost] = proc {|record| record.boost_rate} + assert_equal 10.0, @instance.send(:validate_boost, @instance.configuration[:boost]) + end + + should "accept and return a float" do + @instance.configuration[:boost] = 9.0 + assert_equal 9.0, @instance.send(:validate_boost, @instance.configuration[:boost]) + end + + should "return the default float when the specified is negative" do + @instance.configuration[:boost] = -1.0 + assert_equal 10.0, @instance.send(:validate_boost, @instance.configuration[:boost]) + end + + should "execute the according method when value is a symbol" do + @instance.configuration[:boost] = :irate + assert_equal 8.0, @instance.send(:validate_boost, @instance.configuration[:boost]) + end + + should "return the default boost when there is no valid boost" do + @instance.configuration[:boost] = "boost!" + assert_equal 10.0, @instance.send(:validate_boost, @instance.configuration[:boost]) + end + end + + context "when determining the solr document id" do + should "combine class name and id" do + assert_equal "SolrInstance:10", @instance.solr_id + end + end + + context "when saving the instance to solr" do + context "with indexing disabled" do + setup do + @instance.configuration = {:fields => [:name], :if => nil} + end + + should "just return and do nothing" do + @instance.expects(:solr_add).never + @instance.expects(:solr_destroy).never + assert @instance.solr_save + end + end + + context "with indexing enabled" do + setup do + @instance.configuration = {:fields => [:name], :if => "true", :auto_commit => true} + @instance.stubs(:solr_commit) + @instance.stubs(:solr_add) + @instance.stubs(:to_solr_doc).returns("My test document") + end + + should "add the solr document" do + @instance.expects(:solr_add).with("My test document").once + @instance.solr_save + end + + should "commit to solr" do + @instance.expects(:solr_commit).once + @instance.solr_save + end + + should "not commit if auto_commit is disabled" do + @instance.configuration.merge!(:auto_commit => false) + @instance.expects(:solr_commit).never + @instance.solr_save + end + + should "destroy the document if :if clause is false" do + @instance.configuration.merge!(:if => "false") + @instance.expects(:solr_destroy).once + @instance.solr_save + end + end + end + + context "when destroying an instance in solr" do + setup do + @instance.configuration = {:if => true, :auto_commit => true} + @instance.stubs(:solr_commit) + @instance.stubs(:solr_delete) + end + + should "delete the instance" do + @instance.expects(:solr_delete).with("SolrInstance:10") + @instance.solr_destroy + end + + should "commit to solr" do + @instance.expects(:solr_commit) + @instance.solr_destroy + end + + should "not commit if auto_commit is disabled" do + @instance.configuration.merge!(:auto_commit => false) + @instance.expects(:solr_commit).never + @instance.solr_destroy + end + + context "with indexing disabled" do + should "not contact solr" do + @instance.configuration.merge!(:offline => true, :if => nil) + @instance.expects(:solr_delete).never + @instance.solr_destroy + end + end + end + + context "when converting an instance to a solr document" do + setup do + @instance.configuration = {:if => true, :auto_commit => true, :solr_fields => {:name => {:boost => 9.0}}, :boost => 10.0} + @instance.solr_configuration = {:type_field => "type", :primary_key_field => "pk_id", :default_boost => 25.0} + end + + should "add a document boost" do + assert_equal 10, @instance.to_solr_doc.boost + end + + should "set the solr id" do + assert_equal "SolrInstance:10", @instance.to_solr_doc[:id] + end + + should "set the type field" do + assert_equal "SolrInstance", @instance.to_solr_doc[:type] + end + + should "set the primary key fields" do + assert_equal("10", @instance.to_solr_doc[:pk_id]) + end + + should "add the includes if they were configured" do + @instance.configuration.merge! :include => [:author] + @instance.expects(:add_includes) + @instance.to_solr_doc + end + + context "with a local" do + setup do + @local = Local.new '14.51', '-65.43' + @instance.stubs(:local).returns(@local) + @instance.configuration[:spatial] = true + @fields = @instance.to_solr_doc.fields + end + + should "add the longitude" do + field = @fields.find { |field| field.name.eql? "lng" } + assert_equal @local.longitude, field.value + end + + should "add the latitude" do + field = @fields.find { |field| field.name.eql? "lat" } + assert_equal @local.latitude, field.value + end + end + + context "without a local" do + should "should ignore the spatial option" do + @instance.stubs(:local).returns(nil) + @instance.configuration[:spatial] = true + fields = @instance.to_solr_doc.fields + assert_equal nil, fields.find { |field| field.name.eql? 'lng' } + end + end + + context "with indexed fields" do + should "add fields with type" do + assert_equal "Chunky bacon!", @instance.to_solr_doc[:name_s] + end + + should "add the field boost" do + field = @instance.to_solr_doc.fields.find {|f| f.name.to_s == "name_s"} + assert_equal 9.0, field.boost + end + + should "set the default boost for the field, if none is configured" do + @instance.configuration[:solr_fields][:name][:boost] = nil + field = @instance.to_solr_doc.fields.find {|f| f.name.to_s == "name_s"} + assert_equal 25.0, field.boost + end + + should "not overwrite the type or id field" do + @instance.configuration[:solr_fields] = {:type => {}, :id => {}} + doc = @instance.to_solr_doc + assert_not_equal "humbug", doc[:type] + assert_not_equal "bogus", doc[:id] + end + + should "set the default value if field value is nil" do + @instance.name = nil + @instance.expects(:set_value_if_nil).with('s') + @instance.to_solr_doc + end + + should "not include nil values" do + @instance.name = "" + @instance.stubs(:set_value_if_nil).returns "" + assert_nil @instance.to_solr_doc[:name_s] + end + + should "escape the contents" do + @instance.name = "" + assert_equal "<script>malicious()</script>", @instance.to_solr_doc[:name_s] + end + + should "use an alternate field name if specified in options" do + @instance.stubs(:nickname_for_solr).returns('Nick') + @instance.configuration[:solr_fields].merge! :nickname => {:as => :alias} + doc = @instance.to_solr_doc + assert_not_nil @instance.to_solr_doc.fields.find {|f| f.name.to_s == "alias_s"} + assert_nil @instance.to_solr_doc.fields.find {|f| f.name.to_s == "nickname_s"} + end + + context "when indexing tags" do + setup do + taggings = [Tagging.new('house'), Tagging.new('beach')].sort { |a, b| rand - 0.5 } + @instance.stubs(:taggings).returns(taggings) + @instance.configuration[:taggable] = true + @fields = @instance.to_solr_doc.fields + end + + should "set the field name as tag of type text, so they can be found by a query without filters" do + assert_equal "tag_t", @fields.last.name + end + + should "set the field value with the tag value" do + assert_equal @instance.taggings.last.tag.name, @fields.last.value + end + + should "consider all of them" do + assert_equal @instance.taggings.size * 2, @fields.select { |f| f.name.include? "tag_" }.size + end + + should "facet them" do + assert_equal @fields.select { |f| f.name.include? "tag_t" }.size, + @fields.select { |f| f.name.include? "tag_facet" }.size + end + end + + context "when associations are included" do + setup do + class AssocLabel < String + @@singular = {'people' => 'person'} + def to_s + self + end + def singularize + @@singular[self] + end + end + @assoc = AssocLabel.new('people') + person = {:name => 'Hank Venture', :address => 'Venture Compound'} + @people = [OpenStruct.new(person.merge(:attributes => person))] + @instance.stubs(:people).returns(@people) + @reflection = OpenStruct.new(:macro => :has_many) + @instance.class.stubs(:reflect_on_association).returns(@reflection) + @instance.configuration[:solr_includes] = {@assoc => {}} + @instance.solr_configuration.merge! :default_boost => 35.0 + end + + should "set the default name for the include, if none is configured" do + @instance.configuration[:solr_includes] = {@assoc => {:type => :text}} + doc = @instance.to_solr_doc + assert_not_nil doc.fields.find {|f| f.name.to_s == "person_s"} + end + + should "add the include alias" do + @instance.configuration[:solr_includes] = {@assoc => {:as => :human, :type => :text}} + doc = @instance.to_solr_doc + assert_not_nil doc.fields.find {|f| f.name.to_s == "human_s"} + assert_nil doc.fields.find {|f| f.name.to_s == "person_s"} + end + + should "add the include type" do + @instance.configuration[:solr_includes] = {@assoc => {:type => :date}} + @instance.expects(:get_solr_field_type).with(){|v| true}.at_least_once.returns('s') + @instance.expects(:get_solr_field_type).with(:date).once.returns('d') + doc = @instance.to_solr_doc + end + + should "set the default boost for the include, if none is configured" do + # @instance.configuration[:solr_includes] = {@assoc => {}} + field = @instance.to_solr_doc.fields.find {|f| f.name.to_s == "person_s"} + assert_equal 35.0, field.boost + end + + should "add the include boost" do + @instance.configuration[:solr_includes] = {@assoc => {:boost => 10.0}} + field = @instance.to_solr_doc.fields.find {|f| f.name.to_s == "person_s"} + assert_equal 10.0, field.boost + end + + should "default to a field value with all association attributes" do + # @instance.configuration[:solr_includes] = {@assoc => {}} + field = @instance.to_solr_doc.fields.find {|f| f.name.to_s == "person_s"} + @people.first.attributes.each do |attr, value| + assert_match /#{attr}=#{value}/, field.value + end + end + + should "use a field value from an association method, if one is configured" do + @instance.configuration[:solr_includes] = {@assoc => {:using => :name}} + field = @instance.to_solr_doc.fields.find {|f| f.name.to_s == "person_s"} + assert_equal @people.first.name, field.value + end + + should "use a field value from a proc, if one is configured" do + @instance.configuration[:solr_includes] = {@assoc => {:using => lambda{|r| r.name.reverse}}} + field = @instance.to_solr_doc.fields.find {|f| f.name.to_s == "person_s"} + assert_equal @people.first.name.reverse, field.value + end + + should "join multiple values into a single field unless the :multivalued options is specified" do + @instance.configuration[:solr_includes] = {@assoc => {:multivalued => :true}} + second_person = {:name => 'Dean Venture', :address => 'Venture Compound'} + @people << OpenStruct.new(second_person.merge(:attributes => second_person)) + fields = @instance.to_solr_doc.fields.select {|f| f.name.to_s == "person_s"} + assert_equal @people.size, fields.size + end + + should "include multiple values separately if the :multivalued options is specified" do + # @instance.configuration[:solr_includes] = {@assoc => {}} + second_person = {:name => 'Dean Venture', :address => 'Venture Compound'} + @people << OpenStruct.new(second_person.merge(:attributes => second_person)) + fields = @instance.to_solr_doc.fields.select {|f| f.name.to_s == "person_s"} + assert_not_equal @people.size, fields.size + assert_equal 1, fields.size + end + end + end + end + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/unit/lazy_document_shoulda.rb b/vendor/plugins/acts_as_solr_reloaded/test/unit/lazy_document_shoulda.rb new file mode 100644 index 0000000..e2ceb68 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/unit/lazy_document_shoulda.rb @@ -0,0 +1,34 @@ +require File.expand_path("#{File.dirname(__FILE__)}/test_helper") + +class UserModel; end + +class LazyDocumentTest < Test::Unit::TestCase + context "With a lazy document" do + setup do + @record = stub(:record) + @record.stubs(:is_valid?).returns true + UserModel.stubs(:find).returns @record + @document = ActsAsSolr::LazyDocument.new(1, UserModel) + end + + context "with an uninitialized document" do + should "fetch the record from the database" do + UserModel.expects(:find).with(1).returns(@record) + @document.is_valid? + end + end + + context "with an initialized document" do + should "not fetch the record again" do + @document.is_valid? + @document.expects(:find).never + @document.is_valid? + end + + should "reroute the calls to the record" do + @record.expects(:is_valid?).once + @document.is_valid? + end + end + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/unit/parser_instance.rb b/vendor/plugins/acts_as_solr_reloaded/test/unit/parser_instance.rb new file mode 100644 index 0000000..0f48943 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/unit/parser_instance.rb @@ -0,0 +1,19 @@ +class ActsAsSolr::ParserInstance + include ActsAsSolr::ParserMethods + include ActsAsSolr::CommonMethods + attr_accessor :configuration, :solr_configuration + + def table_name + "documents" + end + + def primary_key + "id" + end + + def find(*args) + [] + end + + public :parse_results, :reorder, :parse_query, :add_scores, :replace_types +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_solr_reloaded/test/unit/parser_methods_shoulda.rb b/vendor/plugins/acts_as_solr_reloaded/test/unit/parser_methods_shoulda.rb new file mode 100644 index 0000000..e01e3ed --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/unit/parser_methods_shoulda.rb @@ -0,0 +1,352 @@ +require File.expand_path("#{File.dirname(__FILE__)}/test_helper") + +class ParserMethodsTest < Test::Unit::TestCase + + context "With a parser instance" do + setup do + @parser = ActsAsSolr::ParserInstance.new + end + + context "When parsing results" do + setup do + @results = stub(:results) + @results.stubs(:total_hits).returns(2) + @results.stubs(:hits).returns([]) + @results.stubs(:max_score).returns 2.1 + @results.stubs(:highlighting).returns [] + @results.stubs(:data).returns({"responseHeader" => {"QTime" => "10.2"}}) + @results.stubs(:header).returns({}) + end + + should "return a SearchResults object" do + assert_equal ActsAsSolr::SearchResults, @parser.parse_results(@results).class + end + + should "set the max score" do + assert_equal 2.1, @parser.parse_results(@results).max_score + end + + should "include the facets" do + @results.stubs(:data).returns({"responseHeader" => {"QTime" => "10.2"}, "facet_counts" => 2}) + assert_equal 2, @parser.parse_results(@results, :facets => true).facets + end + + context "when the format requests objects" do + setup do + @parser.configuration = {:format => :objects} + @parser.solr_configuration = {:primary_key_field => :pk_id} + @results.stubs(:hits).returns [{"pk_id" => 1}, {"pk_id" => 2}] + @parser.stubs(:reorder) + end + + should "query with the record ids" do + @parser.expects(:find).with([1, 2], {}).returns [1, 2] + @parser.parse_results(@results) + end + + should "reorder the records" do + @parser.expects(:reorder).with([], [1, 2]) + @parser.parse_results(@results) + end + + should "add :include if :include was specified" do + @parser.expects(:find).with([1, 2], :include => [:author]).returns [1, 2] + @parser.parse_results(@results, :include => [:author]) + end + end + + context "when the format doesn't request objects" do + setup do + @parser.solr_configuration = {:primary_key_field => "pk_id"} + end + + should "not query the database" do + @parser.expects(:find).never + @parser.parse_results(@results, :format => nil) + end + + should "return just the ids" do + @results.stubs(:hits).returns([{"pk_id" => 1}, {"pk_id" => 2}]) + assert_equal [1, 2], @parser.parse_results(@results, :format => nil).docs + end + + should "ignore the :lazy option" do + @results.stubs(:hits).returns([{"pk_id" => 1}, {"pk_id" => 2}]) + assert_equal [1, 2], @parser.parse_results(@results, :format => :ids, :lazy => true).docs + end + end + + context "with an empty result set" do + setup do + @results.stubs(:total_hits).returns(0) + @results.stubs(:hits).returns([]) + end + + should "return an empty search results set" do + assert_equal 0, @parser.parse_results(@results).total + end + + should "not have any search results" do + assert_equal [], @parser.parse_results(@results).docs + end + end + + context "with a nil result set" do + should "return an empty search results set" do + assert_equal 0, @parser.parse_results(nil).total + end + end + + context "with the scores option" do + should "add the scores" do + @parser.expects(:add_scores).with([], @results) + @parser.parse_results(@results, :scores => true) + end + end + + context "with lazy format" do + setup do + @parser.solr_configuration = {:primary_key_field => :pk_id} + @results.stubs(:hits).returns([{"pk_id" => 1}, {"pk_id" => 2}]) + end + + should "create LazyDocuments for the resulting docs" do + result = @parser.parse_results(@results, :lazy => true) + assert_equal ActsAsSolr::LazyDocument, result.results.first.class + end + + should "set the document id as the record id" do + result = @parser.parse_results(@results, :lazy => true) + assert_equal 1, result.results.first.id + end + + should "set the document class" do + result = @parser.parse_results(@results, :lazy => true) + assert_equal ActsAsSolr::ParserInstance, result.results.first.clazz.class + end + end + + end + + context "when reordering results" do + should "raise an error if arguments don't have the same number of elements" do + assert_raise(RuntimeError) {@parser.reorder([], [1])} + end + + should "reorder the results to match the order of the documents returned by solr" do + thing1 = stub(:thing1) + thing1.stubs(:id).returns 5 + thing2 = stub(:thing2) + thing2.stubs(:id).returns 1 + thing3 = stub(:things3) + thing3.stubs(:id).returns 3 + things = [thing1, thing2, thing3] + reordered = @parser.reorder(things, ['1', '3', '5']) + assert_equal [1, 3, 5], reordered.collect{|thing| thing.id} + end + end + + context "When parsing a query" do + setup do + ActsAsSolr::Post.stubs(:execute) + @parser.stubs(:solr_type_condition).returns "(type:ParserMethodsTest)" + @parser.solr_configuration = {:primary_key_field => "id"} + @parser.configuration = {:solr_fields => nil} + end + + should "set the limit and offset" do + ActsAsSolr::Post.expects(:execute).with {|request, core| + 10 == request.to_hash[:rows] + 20 == request.to_hash[:start] + } + @parser.parse_query "foo", :limit => 10, :offset => 20 + end + + should "set the relevancy of the specified fields and non-filtered terms" do + ActsAsSolr::Post.expects(:execute).with {|request, core| + q = request.to_hash[:q] + q.starts_with?("(aeroplane brasil continent_t:south OR tag_t:(aeroplane brasil)^5 OR description_t:(aeroplane brasil)^3)") or q.starts_with?("(aeroplane brasil continent_t:south OR description_t:(aeroplane brasil)^3 OR tag_t:(aeroplane brasil)^5)") + } + @parser.parse_query "aeroplane brasil continent:south", :relevance => {:tag => 5, :description => 3} + end + + should "set the relevance unless no query specified" do + expected = "(continent_t:south)" + ActsAsSolr::Post.expects(:execute).with {|request, core| + request.to_hash[:q].starts_with? expected + } + @parser.parse_query "continent:south", :relevance => {:tag => 5, :description => 3} + end + + should "set the relevance with simple queries" do + ActsAsSolr::Post.expects(:execute).with {|request, core| + q = request.to_hash[:q] + q.starts_with?("(car OR tag_t:(car)^5 OR description_t:(car)^3)") or q.starts_with?("(car OR description_t:(car)^3 OR tag_t:(car)^5)") + } + @parser.parse_query "car", :relevance => {:tag => 5, :description => 3} + end + + should "not execute anything if the query is nil" do + ActsAsSolr::Post.expects(:execute).never + assert_nil @parser.parse_query(nil) + end + + should "not execute anything if the query is ''" do + ActsAsSolr::Post.expects(:execute).never + assert_nil @parser.parse_query('') + end + + should "raise an error if invalid options where specified" do + assert_raise(RuntimeError) {@parser.parse_query "foo", :invalid => true} + end + + should "add the type" do + ActsAsSolr::Post.expects(:execute).with {|request, core| + request.to_hash[:q].include?("(type:ParserMethodsTest)") + } + @parser.parse_query "foo" + end + + should "append the field types for the specified fields" do + ActsAsSolr::Post.expects(:execute).with {|request, core| + request.to_hash[:q].include?("(username_t:Chunky)") + } + @parser.parse_query "username:Chunky" + end + + should "replace the field types" do + @parser.expects(:replace_types).returns(["active_i:1"]) + ActsAsSolr::Post.expects(:execute).with {|request, core| + request.to_hash[:q].include?("active_i:1") + } + @parser.parse_query "active:1" + end + + should "add score and primary key to field list" do + ActsAsSolr::Post.expects(:execute).with {|request, core| + request.to_hash[:fl] == ('id,score') + } + @parser.parse_query "foo" + end + + should "add highlight options" do + ActsAsSolr::Post.expects(:execute).with {|request, core| + request.to_hash[:hl] == "true" + request.to_hash["hl.fl"] == "title_t" + } + @parser.parse_query "car", :highlight => {:fields => "title"} + end + + should "set the operator" do + ActsAsSolr::Post.expects(:execute).with {|request, core| + "OR" == request.to_hash["q.op"] + } + @parser.parse_query "foo", :operator => :or + end + + should "activate spellcheck" do + ActsAsSolr::Post.expects(:execute).with {|request, core| + request.to_hash[:spellcheck] == true + } + @parser.parse_query "foo" + end + + should "activate spellcheck collation" do + ActsAsSolr::Post.expects(:execute).with {|request, core| + request.to_hash['spellcheck.collate'] == true + } + @parser.parse_query "foo" + end + + context "with the around option" do + should "set the qt as geo" do + ActsAsSolr::Post.expects(:execute).with {|request, core| + request.to_hash[:qt] == ('geo') + } + @parser.parse_query "foo" , :around => {:latitude => '-39.36', + :longitude => '77.4027', + :radius => 1} + end + + should "set the radius" do + ActsAsSolr::Post.expects(:execute).with {|request, core| + request.to_hash[:radius] == 12 + } + @parser.parse_query "foo" , :around => {:latitude => '-39.36', + :longitude => '77.4027', + :radius => 12} + end + + should "set the latitude" do + ActsAsSolr::Post.expects(:execute).with {|request, core| + request.to_hash[:lat] == '-39.36' + } + @parser.parse_query "foo" , :around => {:latitude => '-39.36', + :longitude => '77.4027', + :radius => 12} + end + + should "set the longitude" do + ActsAsSolr::Post.expects(:execute).with {|request, core| + request.to_hash[:long] == '77.4027' + } + @parser.parse_query "foo" , :around => {:latitude => '-39.36', + :longitude => '77.4027', + :radius => 12} + end + end + + context "with the order option" do + should "add the order criteria to the query" do + ActsAsSolr::Post.expects(:execute).with {|request, core| + request.to_hash[:sort].include?("active_t desc") + } + @parser.parse_query "active:1", :order => "active desc" + end + end + + context "with facets" do + end +end + +context "When setting the field types" do + setup do + @parser.configuration = {:solr_fields => {:name => {:type => :string}, + :age => {:type => :integer}}} + end + + should "replace the _t suffix with the real type" do + assert_equal ["name_s:Chunky AND age_i:21"], @parser.replace_types(["name_t:Chunky AND age_t:21"]) + end + + context "with a suffix" do + should "not include the colon when false" do + assert_equal ["name_s"], @parser.replace_types(["name_t"], false) + end + + should "include the colon by default" do + assert_equal ["name_s:Chunky"], @parser.replace_types(["name_t:Chunky"]) + end + end +end + +context "When adding scores" do + setup do + @solr_data = stub(:results) + @solr_data.stubs(:total_hits).returns(1) + @solr_data.stubs(:hits).returns([{"id" => 2, "score" => 2.546}]) + @solr_data.stubs(:max_score).returns 2.1 + + @results = [Array.new] + + @parser.stubs(:record_id).returns(2) + + @parser.solr_configuration = {:primary_key_field => "id"} + end + + should "add the score to the result document" do + assert_equal 2.546, @parser.add_scores(@results, @solr_data).first.last.solr_score + end +end + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/unit/solr_instance.rb b/vendor/plugins/acts_as_solr_reloaded/test/unit/solr_instance.rb new file mode 100644 index 0000000..d551986 --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/unit/solr_instance.rb @@ -0,0 +1,70 @@ +class SolrInstance + include ActsAsSolr::InstanceMethods + attr_accessor :configuration, :solr_configuration, :name + + class << self + include ActsAsSolr::ActsMethods + include ActsAsSolr::ClassMethods + end + + def initialize(name = "Chunky bacon!") + @name = name + end + + def self.primary_key + "id" + end + + def record_id(obj) + 10 + end + + def boost_rate + 10.0 + end + + def irate + 8.0 + end + + def name_for_solr + name + end + + def id_for_solr + "bogus" + end + + def type_for_solr + "humbug" + end + + def get_solr_field_type(args) + "s" + end +end + +class Tagging + attr_reader :tag + + def initialize(name) + @tag = Tag.new name + end +end + +class Tag + attr_reader :name + + def initialize(name) + @name = name + end +end + +class Local + attr_reader :longitude, :latitude + + def initialize(long, lati) + @longitude = long + @latitude = lati + end +end diff --git a/vendor/plugins/acts_as_solr_reloaded/test/unit/test_helper.rb b/vendor/plugins/acts_as_solr_reloaded/test/unit/test_helper.rb new file mode 100644 index 0000000..ac6cb3a --- /dev/null +++ b/vendor/plugins/acts_as_solr_reloaded/test/unit/test_helper.rb @@ -0,0 +1,30 @@ +dir = File.dirname(__FILE__) +$:.unshift(File.join(File.expand_path(dir), "..", "..", "lib")) + +require 'rubygems' +require 'test/unit' +require 'acts_as_solr' +require 'mocha' +require 'active_support' +require 'logger' +require File.expand_path("#{dir}/solr_instance") +require File.expand_path("#{dir}/parser_instance") +require 'erb' +require 'ostruct' +require 'mongo_mapper' + +if RUBY_VERSION =~ /^1\.9/ + puts "\nRunning the unit test suite doesn't as of yet work with Ruby 1.9, because Mocha hasn't yet been updated to use minitest." + puts + exit 1 +end + +require 'mocha' +gem 'thoughtbot-shoulda' +require 'shoulda' + +class Rails + def self.logger + Logger.new(StringIO.new) + end +end -- libgit2 0.21.2