asari 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -16,6 +16,20 @@ for easy integration with your Rails apps.
16
16
  asari = Asari.new("my-search-domain-asdfkljwe4") # CloudSearch search domain
17
17
  asari.add_item("1", { :name => "Tommy Morgan", :email => "tommy@wellbredgrapefruit.com"})
18
18
  asari.search("tommy") #=> ["1"] - a list of document IDs
19
+
20
+ #### Sandbox Mode
21
+
22
+ Because there is no "local" version of CloudSearch, and search instances can be
23
+ kind of expensive, you shouldn't have to have a development version of your
24
+ index set up in order to use Asari. Because of that, Asari has a "sandbox" mode
25
+ where it does nothing with add/update/delete requests and just returns an empty
26
+ collection for any searches. This sandbox mode is enabled by default - any time
27
+ you want to actually connect to the search index, just do the following:
28
+
29
+ Asari.mode = :production
30
+
31
+ You can turn the sandbox back on, if you like, by setting the mode to `:sandbox`
32
+ again.
19
33
 
20
34
  #### Pagination
21
35
 
@@ -64,6 +78,25 @@ with your AR objects as follows:
64
78
  @user.asari_update_in_index
65
79
  @user.asari_remove_from_index
66
80
 
81
+ You can also specify a :when option, like so:
82
+
83
+ asari_index("search-domain-for-users", [:name, :email, :twitter_handle,
84
+ :favorite_sweater], :when => :indexable)
85
+
86
+ or
87
+
88
+ asari_index("search-domain-for-users", [:name, :email, :twitter_handle,
89
+ :favorite_sweater], :when => Proc.new { |user| !user.admin && user.indexable })
90
+
91
+ This provides a way to mark records that shouldn't be in the index. The :when
92
+ option can be either a symbol - indicating a method on the object - or a Proc
93
+ that accepts the object as its first parameter. If the method/Proc returns true
94
+ when the object is created, the object is indexed - otherwise it is left out of
95
+ the index. If the method/Proc returns true when the object is updated, the
96
+ object is indexed - otherwise it is deleted from the index (if it has already
97
+ been added). This lets you be sure that you never have inappropriate data in
98
+ your search index.
99
+
67
100
  Because index updates are done as part of the AR lifecycle by default, you also
68
101
  might want to have control over how Asari handles index update errors - it's
69
102
  kind of problematic, if, say, users can't sign up on your site because
@@ -40,29 +40,49 @@ class Asari
40
40
  # search_domain - the CloudSearch domain to use for indexing this model.
41
41
  # fields - an array of Symbols representing the list of fields that
42
42
  # should be included in this index.
43
+ # options - a hash of extra options to consider when indexing this
44
+ # model. Right now, only one option is available:
45
+ # when - a string or symbol representing a method name, or a Proc to
46
+ # evaluate to determine if this model object should be indexed. On
47
+ # creation, if the method or Proc specified returns false, the
48
+ # model will not be indexed. On update, if the method or Proc
49
+ # specified returns false, the model will be removed from the
50
+ # index (if it exists there).
43
51
  #
44
52
  # Examples:
45
53
  # class User < ActiveRecord::Base
46
54
  # include Asari::ActiveRecord
47
55
  #
48
56
  # asari_index("my-companies-users-asglkj4rsagkjlh34", [:name, :email])
57
+ # # or
58
+ # asari_index("my-companies-users-asglkj4rsagkjlh34", [:name, :email], :when => :should_be_indexed)
59
+ # # or
60
+ # asari_index("my-companies-users-asglkj4rsagkjlh34", [:name, :email], :when => Proc.new({ |user| user.published && !user.admin? }))
49
61
  #
50
- def asari_index(search_domain, fields)
51
- self.class_variable_set(:@@asari, Asari.new(search_domain))
52
- self.class_variable_set(:@@fields, fields)
62
+ def asari_index(search_domain, fields, options = {})
63
+ self.class_variable_set(:@@asari_instance, Asari.new(search_domain))
64
+ self.class_variable_set(:@@asari_fields, fields)
65
+ self.class_variable_set(:@@asari_when, options.delete(:when))
53
66
  end
54
67
 
55
68
  def asari_instance
56
- self.class_variable_get(:@@asari)
69
+ self.class_variable_get(:@@asari_instance)
57
70
  end
58
71
 
59
72
  def asari_fields
60
- self.class_variable_get(:@@fields)
73
+ self.class_variable_get(:@@asari_fields)
74
+ end
75
+
76
+ def asari_when
77
+ self.class_variable_get(:@@asari_when)
61
78
  end
62
79
 
63
80
  # Internal: method for adding a newly created item to the CloudSearch
64
81
  # index. Should probably only be called from asari_add_to_index above.
65
82
  def asari_add_item(obj)
83
+ if self.asari_when
84
+ return unless asari_should_index?(obj)
85
+ end
66
86
  data = {}
67
87
  self.asari_fields.each do |field|
68
88
  data[field] = obj.send(field) || ""
@@ -75,6 +95,12 @@ class Asari
75
95
  # Internal: method for updating a freshly edited item to the CloudSearch
76
96
  # index. Should probably only be called from asari_update_in_index above.
77
97
  def asari_update_item(obj)
98
+ if self.asari_when
99
+ unless asari_should_index?(obj)
100
+ self.asari_remove_item(obj)
101
+ return
102
+ end
103
+ end
78
104
  data = {}
79
105
  self.asari_fields.each do |field|
80
106
  data[field] = obj.send(field)
@@ -92,6 +118,17 @@ class Asari
92
118
  self.asari_on_error(e)
93
119
  end
94
120
 
121
+ # Internal: method for looking at the when method/Proc (if defined) to
122
+ # determine whether this model should be indexed.
123
+ def asari_should_index?(object)
124
+ when_test = self.asari_when
125
+ if when_test.is_a? Proc
126
+ return Proc.call(object)
127
+ else
128
+ return object.send(when_test)
129
+ end
130
+ end
131
+
95
132
  # Public: method for searching the index for the specified term and
96
133
  # returning all model objects that match.
97
134
  #
@@ -1,3 +1,3 @@
1
1
  class Asari
2
- VERSION = "0.6.0"
2
+ VERSION = "0.7.0"
3
3
  end
@@ -5,7 +5,7 @@ describe Asari do
5
5
  describe "when CloudSearch is responding without error" do
6
6
  before :each do
7
7
  @asari = double()
8
- ActiveRecordFake.class_variable_set(:@@asari, @asari)
8
+ ActiveRecordFake.class_variable_set(:@@asari_instance, @asari)
9
9
  end
10
10
 
11
11
  it "correctly sets up a before_destroy listener" do
@@ -60,7 +60,7 @@ describe Asari do
60
60
 
61
61
  describe "When CloudSearch is being a problem" do
62
62
  before :each do
63
- ActiveRecordFake.class_variable_set(:@@asari, Asari.new("test-domain"))
63
+ ActiveRecordFake.class_variable_set(:@@asari_instance, Asari.new("test-domain"))
64
64
  stub_const("HTTParty", double())
65
65
  HTTParty.stub(:post).and_return(fake_error_response)
66
66
  HTTParty.stub(:get).and_return(fake_error_response)
@@ -0,0 +1,51 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Asari do
4
+ describe Asari::ActiveRecord do
5
+ describe "conditional indexing" do
6
+ describe "when a :when option is provided" do
7
+ before :each do
8
+ @arcs = ARConditionalsSpy.new
9
+ @arcs.be_indexable = false
10
+ @asari = double()
11
+ ARConditionalsSpy.class_variable_set(:@@asari_instance, @asari)
12
+ end
13
+
14
+ it "doesn't add to the index if the :when option returns false" do
15
+ expect(@arcs.was_asked).to eq(false)
16
+ @arcs.asari_add_to_index
17
+ expect(@arcs.was_asked).to eq(true)
18
+ end
19
+
20
+ it "doesn't add to the index if the :when option returns false" do
21
+ expect(@arcs.was_asked).to eq(false)
22
+ @arcs.asari_add_to_index
23
+ expect(@arcs.was_asked).to eq(true)
24
+ end
25
+
26
+ it "does add to the index if the :when option returns true" do
27
+ expect(@arcs.was_asked).to eq(false)
28
+ @arcs.be_indexable = true
29
+ @asari.should_receive(:add_item).with(1, { :name => "Tommy", :email => "some@email.com"})
30
+ @arcs.asari_add_to_index
31
+ expect(@arcs.was_asked).to eq(true)
32
+ end
33
+
34
+ it "deletes the item from the index if the :when option returns false when the item is updated" do
35
+ expect(@arcs.was_asked).to eq(false)
36
+ @asari.should_receive(:remove_item).with(1)
37
+ @arcs.asari_update_in_index
38
+ expect(@arcs.was_asked).to eq(true)
39
+ end
40
+
41
+ it "updates the item in the index if the :when option returns true when the item is updated" do
42
+ expect(@arcs.was_asked).to eq(false)
43
+ @arcs.be_indexable = true
44
+ @asari.should_receive(:update_item).with(1, { :name => "Tommy", :email => "some@email.com"})
45
+ @arcs.asari_update_in_index
46
+ expect(@arcs.was_asked).to eq(true)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -34,6 +34,7 @@ module ActiveRecord
34
34
  end
35
35
 
36
36
  class ActiveRecordFake
37
+
37
38
  class << self
38
39
  def before_destroy(sym)
39
40
  @before_destroy = sym
@@ -78,3 +79,55 @@ class ActiveRecordFakeWithErrorOverride < ActiveRecordFake
78
79
  false
79
80
  end
80
81
  end
82
+
83
+ class ARConditionalsSpy
84
+ attr_accessor :be_indexable
85
+ attr_accessor :was_asked
86
+
87
+ class << self
88
+ def before_destroy(sym)
89
+ @before_destroy = sym
90
+ end
91
+
92
+ def after_create(sym)
93
+ @after_create = sym
94
+ end
95
+
96
+ def after_update(sym)
97
+ @after_update = sym
98
+ end
99
+
100
+ def find(*args)
101
+ if args.size > 0
102
+ return [ARConditionalsSpy.new]
103
+ else
104
+ raise ActiveRecord::RecordNotFound
105
+ end
106
+ end
107
+ end
108
+
109
+ include Asari::ActiveRecord
110
+
111
+ asari_index("test-domain", [:name, :email], :when => :indexable)
112
+
113
+ def initialize
114
+ @was_asked = false
115
+ end
116
+
117
+ def id
118
+ 1
119
+ end
120
+
121
+ def name
122
+ "Tommy"
123
+ end
124
+
125
+ def email
126
+ "some@email.com"
127
+ end
128
+
129
+ def indexable
130
+ @was_asked = true
131
+ @be_indexable
132
+ end
133
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asari
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-12 00:00:00.000000000 Z
12
+ date: 2012-07-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: httparty
16
- requirement: &70109076129460 !ruby/object:Gem::Requirement
16
+ requirement: &70205905685040 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70109076129460
24
+ version_requirements: *70205905685040
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &70109076128860 !ruby/object:Gem::Requirement
27
+ requirement: &70205905684100 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70109076128860
35
+ version_requirements: *70205905684100
36
36
  description: Asari s a Ruby interface for AWS CloudSearch
37
37
  email:
38
38
  - tommy@wellbredgrapefruit.com
@@ -53,6 +53,7 @@ files:
53
53
  - spec/active_record_spec.rb
54
54
  - spec/asari_spec.rb
55
55
  - spec/collection_spec.rb
56
+ - spec/conditionals_spec.rb
56
57
  - spec/documents_spec.rb
57
58
  - spec/search_spec.rb
58
59
  - spec_helper.rb
@@ -84,6 +85,7 @@ test_files:
84
85
  - spec/active_record_spec.rb
85
86
  - spec/asari_spec.rb
86
87
  - spec/collection_spec.rb
88
+ - spec/conditionals_spec.rb
87
89
  - spec/documents_spec.rb
88
90
  - spec/search_spec.rb
89
91
  has_rdoc: