lib/pose.rb in pose-0.3 vs lib/pose.rb in pose-1.0.0

- old
+ new

@@ -1,192 +1,10 @@ # Note (KG): Need to include the rake DSL here to prevent deprecation warnings in the Rakefile. require 'rake' include Rake::DSL if defined? Rake::DSL - -# Polymorphic search for ActiveRecord objects. -module Pose - extend ActiveSupport::Concern - - # By default, doesn't run in tests. - # Set this to true to test the search functionality. - CONFIGURATION = { :search_in_tests => false } - - included do - has_many :pose_assignments, :as => :posable, :dependent => :delete_all - has_many :pose_words, :through => :pose_assignments - - after_save :update_pose_index - before_destroy :delete_pose_index - - cattr_accessor :pose_content - end - - # Asks if model should perform search. - # - # @return [false, true] - def perform_search? - !(Rails.env == 'test' and !CONFIGURATION[:search_in_tests]) - end - - module InstanceMethods - - # Updates the associated words for this object in the database. - def update_pose_index - update_pose_words if perform_search? - end - - # Removes this objects from the search index. - def delete_pose_index - self.pose_words.clear if perform_search? - end - - # Helper method. - # Updates the search words with the text returned by search_strings. - def update_pose_words - - # Step 1: get an array of all words for the current object. - search_string = instance_eval &(self.class.pose_content) - new_words = search_string.to_s.split(' ').map { |word| Pose.root_word(word) }.flatten.uniq - - # Step 2: Add new words to the search index. - Pose.get_words_to_add(self.pose_words, new_words).each do |word_to_add| - self.pose_words << PoseWord.find_or_create_by_text(word_to_add) - end - - # Step 3: Remove now obsolete words from search index. - Pose.get_words_to_remove(self.pose_words, new_words).each do |word_to_remove| - self.pose_words.delete word_to_remove - end - end - end - - class <<self - - # Returns all words that begin with the given query string. - # This can be used for autocompletion functionality. - # - # @param [String] - # @return [Array<String>] - def autocomplete_words query - return [] if query.blank? - PoseWord.where('text LIKE ?', "#{Pose.root_word(query)[0]}%").map(&:text) - end - - # Returns all strings that are in new_words, but not in existing_words. - # Helper method. - # - # @param [Array<String>] existing_words The words that are already associated with the object. - # @param [Array<String>] new_words The words thet the object should have from now on. - # - # @return [Array<String>] The words that need to be added to the existing_words array. - def get_words_to_add existing_words, new_words - new_words - existing_words.map(&:text) - end - - # Helper method. - # Returns the id of all word objects that are in existing_words, but not in new_words. - # - # @param [Array<String>] existing_words The words that are already associated with the object. - # @param [Array<String>] new_words The words thet the object should have from now on. - # - # @return [Array<String>] The words that need to be removed from the existing_words array. - def get_words_to_remove existing_words, new_words - existing_words.map do |existing_word| - existing_word unless new_words.include?(existing_word.text) - end.compact - end - - # Returns whether the given string is a URL. - # - # @param [String] word The string to check. - # - # @return [Boolean] - def is_url? word - URI::parse(word).scheme == 'http' - rescue URI::InvalidURIError - false - end - - # Simplifies the given word to a generic search form. - # - # @param [String] raw_word The word to make searchable. - # - # @return [String] The stemmed version of the word. - def root_word raw_word - result = [] - raw_word_copy = raw_word[0..-1] - raw_word_copy.gsub! '%20', ' ' - raw_word_copy.gsub! /[()*<>'",;\?\-\=&%#]/, ' ' - raw_word_copy.gsub! /\s+/, ' ' - raw_word_copy.split(' ').each do |word| - if Pose.is_url?(word) - result.concat word.split(/[\.\/\:]/).delete_if(&:blank?) - else - word.gsub! /[\-\/\._:]/, ' ' - word.gsub! /\s+/, ' ' - word.split(' ').each do |w| - stemmed_word = w.parameterize.singularize - result.concat stemmed_word.split ' ' - end - end - end - result.uniq - end - - # Returns all objects matching the given query. - # - # @param [String] query - # @param (Class|[Array<Class>]) classes - # @param [Number?] limit Optional limit. - # - # @return [Hash<Class, ActiveRecord::Relation>] - def search query, classes, limit = nil - - # Turn 'classes' into an array. - classes = [classes].flatten - classes_names = classes.map &:name - classes_names = classes_names[0] if classes_names.size == 1 - - # Get the ids of the results. - result_classes_and_ids = {} - query.split(' ').each do |query_word| - current_word_classes_and_ids = {} - classes.each { |clazz| current_word_classes_and_ids[clazz.name] = [] } - query = PoseAssignment.joins(:pose_word) \ - .where('pose_words.text LIKE ?', "#{query_word}%") \ - .where('posable_type IN (?)', classes_names) - query.each do |pose_assignment| - current_word_classes_and_ids[pose_assignment.posable_type] << pose_assignment.posable_id - end - - current_word_classes_and_ids.each do |class_name, ids| - if result_classes_and_ids.has_key? class_name - result_classes_and_ids[class_name] = result_classes_and_ids[class_name] & ids - else - result_classes_and_ids[class_name] = ids - end - end - end - - # Load the results by id. - {}.tap do |result| - result_classes_and_ids.each do |class_name, ids| - result_class = Kernel.const_get class_name - - if ids.any? && classes.include?(result_class) - ids = ids.slice(0, limit) if limit - result[result_class] = result_class.where :id => ids - else - result[result_class] = [] - end - end - end - end - end -end - - -require 'pose/posifier' -require "pose/railtie" if defined? Rails +require 'pose/static_helpers' +require 'pose/base_additions' +require 'pose/model_additions' +require 'pose/railtie' if defined? Rails require 'pose_assignment' require 'pose_word'