Sha256: f3216489c8799b0224cef403fb58b1d293666e0d3a1a3f08004e6fa70655f5f9

Contents?: true

Size: 1.96 KB

Versions: 4

Compression:

Stored size: 1.96 KB

Contents

module MongoMapperExt
  module Filter
    def self.included(klass)
      begin
        require 'lingua/stemmer'
      rescue LoadError
        $stderr.puts "install ruby-stemmer `gem install ruby-stemmer` to activate the full text search support"
      end

      klass.class_eval do
        extend ClassMethods

        key :_keywords, Array
        ensure_index :_keywords

        before_save :_update_keywords
      end
    end

    module ClassMethods
      def filterable_keys(*keys)
        @filterable_keys ||= Set.new
        @filterable_keys += keys

        @filterable_keys
      end

      def language(lang = 'en')
        @language ||= lang
      end

      def filter(query, opts = {})
        q = query.downcase.split.map do |k|
          Regexp.escape(k)
        end.join("|")
        if opts[:per_page]
          self.paginate(opts.deep_merge(:conditions => {:_keywords => /^(#{q}).*/ }))
        else
          self.all(opts.deep_merge(:conditions => {:_keywords => /^(#{q}).*/ }))
        end
      end
    end

    protected
    def _update_keywords
      lang = self.class.language
      if lang.kind_of?(Symbol)
        lang = send(lang)
      elsif lang.kind_of?(Proc)
        lang = lang.call(self)
      end

      stemmer = nil
      if defined?(Lingua)
        stemmer = Lingua::Stemmer.new(:language => lang)
      end

      self._keywords = []
      self.class.filterable_keys.each do |key|
        self._keywords += keywords_for_value(read_attribute(key), stemmer)
      end
    end

    private
    def keywords_for_value(val, stemmer=nil)
      if val.kind_of?(String)
        val.downcase.split.map do |word|
          stem = word
          if stemmer
            stem = stemmer.stem(word)
          end

          if stem != word
            [stem, word]
          else
            word
          end
        end.flatten
      elsif val.kind_of?(Array)
        val.map { |e| keywords_for_value(e, stemmer) }.flatten
      else
        [val]
      end
    end
  end
end

Version data entries

4 entries across 4 versions & 1 rubygems

Version Path
mongomapper_ext-0.1.3 lib/mongomapper_ext/filter.rb
mongomapper_ext-0.1.2 lib/mongomapper_ext/filter.rb
mongomapper_ext-0.1.1 lib/mongomapper_ext/filter.rb
mongomapper_ext-0.1.0 lib/mongomapper_ext/filter.rb