activesearch 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -4,39 +4,42 @@ This gem allows any class to be indexed by the chosen fulltext search engine.
4
4
 
5
5
  ## Installation
6
6
 
7
- Add this line to your application's Gemfile:
7
+ Depending on the chosen engine, you need to require a dependency and then activesearch on your Gemfile:
8
8
 
9
- gem 'activesearch'
10
-
11
- And then execute:
9
+ ###Mongoid
12
10
 
13
- $ bundle
11
+ gem 'mongoid'
12
+ gem 'activesearch'
13
+
14
+ This is not a fulltext search engine, but it's a good solution for those users that don't have access to anything else.
15
+ It works by storing keywords taken from the specified fields and storing them in an Array field, which would be indexed.
16
+
17
+ ###elasticsearch
14
18
 
15
- Or install it yourself as:
19
+ gem 'tire'
20
+ gem 'activesearch'
16
21
 
17
- $ gem install activesearch
22
+ ##Configuration
18
23
 
19
- ## Supported engines
24
+ Add this to your model:
25
+
26
+ search_by :title, :body, store: [:slug]
27
+
28
+ the :store option allows you to retrieve that value but it won't be used for search.
20
29
 
21
- ###Mongoid
30
+ ## Querying
31
+
32
+ ActiveSearch.search("some words").first.to_hash["title"]
33
+
34
+ You can access the stored fields with to_hash, so you don't need to fetch the real document.
22
35
 
23
- This is not a fulltext search engine, but it's a good solution for those users that don't have access to anything else.
24
- It works by storing keywords taken from the specified fields and storing them in an Array field, which would be indexed.
25
- search() method will return a Mongod::Criteria, so you can chain it with further scopes, like pagination.
26
- You won't get original documents though.
36
+ ## Testing
27
37
 
28
- ## Usage
38
+ Run specs with this command:
29
39
 
30
- class SomeModel
31
- # [...] field definitions if needed
32
- include ActiveSearch::Engine # "Engine" being your chosen engine ie. "Mongoid"
33
-
34
- search_on :title, :body, store: [:title]
35
- end
36
-
37
- # Access the stored fields so you don't need to fetch the real document
38
- ActiveSearch.search("some words").first.stored["title"]
40
+ bundle exec parallel_rspec spec/
39
41
 
42
+ Since different engines define their own version of ActiveSearch, running specs on a single process will break.
40
43
 
41
44
  ## Contributing
42
45
 
data/activesearch.gemspec CHANGED
@@ -19,5 +19,8 @@ Gem::Specification.new do |gem|
19
19
 
20
20
  gem.add_development_dependency "rspec"
21
21
  gem.add_development_dependency "bson_ext"
22
- gem.add_development_dependency "mongoid", "~> 2.4"
23
- end
22
+ gem.add_development_dependency "active_attr"
23
+ gem.add_development_dependency "mongoid", "~> 2"
24
+ gem.add_development_dependency "tire"
25
+ gem.add_development_dependency "parallel_tests"
26
+ end
data/elasticsearch.log ADDED
@@ -0,0 +1,24 @@
1
+ # 2012-10-31 15:41:49:965 [HEAD] ("elastic_search_models")
2
+ #
3
+ curl -I "http://localhost:9200/elastic_search_models"
4
+
5
+ # 2012-10-31 15:41:49:988 [200]
6
+ #
7
+ # ""
8
+
9
+ # 2012-10-31 15:41:50:002 [HEAD] ("another_elastic_search_models")
10
+ #
11
+ curl -I "http://localhost:9200/another_elastic_search_models"
12
+
13
+ # 2012-10-31 15:41:50:002 [200]
14
+ #
15
+ # ""
16
+
17
+ # 2012-10-31 15:41:50:007 [_search] (["_all"])
18
+ #
19
+ curl -X GET "http://localhost:9200/_all/_search?query%5Bstring%5D=findable&pretty=true" -d '{}'
20
+
21
+ # 2012-10-31 15:41:50:008 [200] (1 msec)
22
+ #
23
+ # {"took":1,"timed_out":false,"_shards":{"total":10,"successful":10,"failed":0},"hits":{"total":0,"max_score":null,"hits":[]}}
24
+
@@ -0,0 +1,26 @@
1
+ require "activesearch/result"
2
+
3
+ module ActiveSearch
4
+ module ElasticSearch
5
+ class Proxy
6
+ include Enumerable
7
+
8
+ def initialize(text)
9
+ @text = text
10
+ end
11
+
12
+ def each(&block)
13
+ search.results.each { |result| block.call(Result.new(result)) }
14
+ end
15
+
16
+ protected
17
+ def search
18
+ @search ||= Tire.search('_all') do |search|
19
+ search.query do |query|
20
+ query.text("_all", @text)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,30 @@
1
+ require "active_support/core_ext"
2
+ require "activesearch/elastic_search/proxy"
3
+
4
+ module ActiveSearch
5
+
6
+ def self.search(text)
7
+ ElasticSearch::Proxy.new(text)
8
+ end
9
+
10
+ module ElasticSearch
11
+ def self.included(base)
12
+ base.extend ClassMethods
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+ def search_by(*fields)
18
+ options = fields.pop if fields.last.is_a?(Hash)
19
+ include Tire::Model::Search
20
+ include Tire::Model::Callbacks
21
+
22
+ mapping do
23
+ indexes :type
24
+ indexes :id, as: :original_id
25
+ fields.each { |f| indexes f }
26
+ (Array(options[:store]) - fields).each { |f| indexes f, :index => :no }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -3,24 +3,28 @@ module ActiveSearch
3
3
  class Model
4
4
  include ::Mongoid::Document
5
5
 
6
- field :type, type: String
7
- field :original_id, type: BSON::ObjectId
8
- field :keywords
9
- field :stored, type: Hash, default: {}
6
+ field :_original_type, type: String
7
+ field :_original_id, type: BSON::ObjectId
8
+ field :_keywords
9
+ field :_stored, type: Hash, default: {}
10
10
 
11
- index :keywords
12
- index [:type, :original_id], unique: true
11
+ index :_keywords
12
+ index [:_original_type, :_original_id], unique: true
13
+
14
+ def to_hash
15
+ _stored
16
+ end
13
17
 
14
18
  def store_fields(original, fields, options)
15
19
  if options && options[:store]
16
20
  options[:store].each do |f|
17
- self.stored[f] = original[f] if original.send("#{f}_changed?")
21
+ self._stored[f] = original[f] if original.send("#{f}_changed?")
18
22
  end
19
23
  end
20
24
  end
21
25
 
22
26
  def refresh_keywords(original, fields)
23
- self.keywords = fields.select { |f| original.fields[f.to_s] }.inject([]) do |memo,f|
27
+ self._keywords = fields.select { |f| original.fields[f.to_s] }.inject([]) do |memo,f|
24
28
 
25
29
  if original.fields[f.to_s].localized?
26
30
  memo += original.send("#{f}_translations").map do |locale,translation|
@@ -30,11 +34,16 @@ module ActiveSearch
30
34
  original[f] ? memo += original[f].downcase.split : memo
31
35
  end
32
36
  end
33
- self.keywords.uniq!
37
+ self._keywords.uniq!
38
+ end
39
+
40
+ def self.deindex(original)
41
+ ActiveSearch::Mongoid::Model.where(_original_type: original.class.to_s, _original_id: original.id).destroy
34
42
  end
35
43
 
36
44
  def self.reindex(original, fields, options)
37
- doc = self.find_or_initialize_by(type: original.class.to_s, original_id: original.id)
45
+ return unless fields.any? { |f| original.send("#{f}_changed?") }
46
+ doc = find_or_initialize_by(_original_type: original.class.to_s, _original_id: original.id)
38
47
  doc.store_fields(original, fields, options)
39
48
  doc.refresh_keywords(original, fields)
40
49
  doc.save
@@ -4,7 +4,8 @@ module ActiveSearch
4
4
 
5
5
  # TODO: Wrap this so all engines behave consistently
6
6
  def self.search(text)
7
- Mongoid::Model.where(:keywords.in => text.split + text.split.map { |word| "#{I18n.locale}:#{word}"})
7
+ text = text.split(/\s+/)
8
+ Mongoid::Model.where(:_keywords.in => text + text.map { |word| "#{I18n.locale}:#{word}"})
8
9
  end
9
10
 
10
11
  module Mongoid
@@ -12,17 +13,29 @@ module ActiveSearch
12
13
  base.extend ClassMethods
13
14
  end
14
15
 
16
+ protected
17
+ def reindex
18
+ ActiveSearch::Mongoid::Model.reindex(self, self.class.search_fields, self.class.search_options)
19
+ end
20
+
21
+ def deindex
22
+ ActiveSearch::Mongoid::Model.deindex(self)
23
+ end
24
+
15
25
  module ClassMethods
16
- def search_on(*fields)
17
- # TODO: Use inheritable class variables, so ActiveSearch::Mongoid::Model can get fields and options from there
18
- self.class_eval <<-EOV
19
- after_save do
20
- fields = #{fields}
21
- options = fields.pop if fields.last.is_a?(Hash)
22
- return unless fields.any? { |f| self.send("\#{f}_changed?") }
23
- ActiveSearch::Mongoid::Model.reindex(self, fields, options)
24
- end
25
- EOV
26
+ def search_options
27
+ @search_options
28
+ end
29
+
30
+ def search_fields
31
+ @search_fields
32
+ end
33
+
34
+ def search_by(*fields)
35
+ @search_options = fields.pop if fields.last.is_a?(Hash)
36
+ @search_fields = fields
37
+ self.after_save :reindex
38
+ self.after_destroy :deindex
26
39
  end
27
40
  end
28
41
  end
@@ -0,0 +1,13 @@
1
+ module ActiveSearch
2
+ class Result < Hash
3
+ def initialize(result)
4
+ result.to_hash.each do |k,v|
5
+ self[k.to_s] = v unless v.nil?
6
+ end
7
+ end
8
+
9
+ def attributes
10
+ self
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module ActiveSearch
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
data/lib/activesearch.rb CHANGED
@@ -1 +1 @@
1
- require "activesearch/version"
1
+ require "activesearch/version"