cloud_search_rails 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/Guardfile CHANGED
@@ -1,7 +1,7 @@
1
1
  # A sample Guardfile
2
2
  # More info at https://github.com/guard/guard#readme
3
3
 
4
- guard 'rspec', :version => 2 do
4
+ guard 'rspec', :version => 2, :opts => "--format nested" do
5
5
  watch(%r{^spec/.+_spec\.rb$})
6
6
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
7
  watch('spec/spec_helper.rb') { "spec" }
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "cloud_search_rails"
8
- s.version = "0.0.1"
8
+ s.version = "0.0.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Dan Langevin"]
12
- s.date = "2012-04-28"
12
+ s.date = "2012-05-01"
13
13
  s.description = "Rails integration for CloudSearch"
14
14
  s.email = "dan.langevin@lifebooker.com"
15
15
  s.extra_rdoc_files = [
@@ -4,6 +4,10 @@ require 'cloud_search_rails/exceptions'
4
4
  require 'cloud_search_rails/index'
5
5
  require 'cloud_search_rails/search'
6
6
 
7
+ if defined?(Rails)
8
+ require 'cloud_search_rails/railtie'
9
+ end
10
+
7
11
  module CloudSearchRails
8
12
 
9
13
  def self.connection(domain = "default")
@@ -35,7 +39,7 @@ module CloudSearchRails
35
39
 
36
40
  # ensure config is all set
37
41
  unless self.cloud_search_domain.present?
38
- raise CloudSearchRails::MissingSearchDomain.new
42
+ raise CloudSearchRails::MissingSearchDomain.new(self)
39
43
  end
40
44
  end
41
45
 
@@ -1,3 +1,8 @@
1
1
  module CloudSearchRails
2
- class MissingSearchDomain < Exception; end;
2
+ class MissingSearchDomain < Exception
3
+ # constructor
4
+ def initialize(klass)
5
+ super("You must define a cloud_search_domain for #{klass}")
6
+ end
7
+ end
3
8
  end
@@ -35,6 +35,8 @@ module CloudSearchRails
35
35
  d.id = self.id
36
36
  d.lang = "en"
37
37
  d.version = self.updated_at.to_i
38
+ # class name
39
+ d.add_field("type", self.class.base_class.name)
38
40
  self.cloud_search_data.each_pair do |k,v|
39
41
  d.add_field(k.to_s, v.to_s)
40
42
  end
@@ -1,31 +1,83 @@
1
1
  module CloudSearchRails
2
2
 
3
3
  module Search
4
+
4
5
  def self.included(klass)
5
6
  klass.send(:extend, ClassMethods)
6
7
  klass.class_eval do
7
- named_scope :cloud_search_rails_scope, lambda{|*ids|
8
+ # lambda block for the scope
9
+ scope_def = lambda{|*ids|
8
10
  {
9
11
  :conditions => [
10
12
  "#{self.table_name}.#{self.primary_key} IN (?)", ids.flatten
11
13
  ]
12
14
  }
13
15
  }
16
+ named_scope :cloud_search_rails_scope, scope_def do
17
+ include WillPaginateMethods
18
+ end
19
+ end
20
+ end
21
+
22
+ # methods of WillPaginate compatibility
23
+ module WillPaginateMethods
24
+
25
+ attr_accessor :current_page, :per_page, :total_entries
26
+
27
+ # calculated offset given the current page and the number
28
+ # of entries per page
29
+ def offset
30
+ (self.current_page - 1) * self.per_page
31
+ end
32
+
33
+ # total number of pages
34
+ def total_pages
35
+ (self.total_entries.to_f / self.per_page.to_f).ceil
14
36
  end
37
+
15
38
  end
16
39
 
17
40
  module ClassMethods
18
41
 
19
42
  # return a scope with the subset of ids
20
- def cloud_search(query = nil, &block)
21
- search_request = AWSCloudSearch::SearchRequest.new.tap do |req|
22
- req.q = query if query.present?
23
- yield(req) if block_given?
24
- end
43
+ def cloud_search(*args)
44
+ opts = {
45
+ :page => 1,
46
+ :per_page => 20
47
+ }
48
+ opts = opts.merge(args.extract_options!)
49
+ query = args.first
50
+
51
+ response = self.cloud_search_response(args.first, opts)
52
+ ids = response.hits.collect{|h| h["id"]}
53
+
54
+ proxy = self.cloud_search_rails_scope(ids)
55
+ proxy.per_page = opts[:per_page]
56
+ proxy.current_page = opts[:page]
57
+ proxy.total_entries = response.found
58
+ proxy
59
+ end
25
60
 
26
- res = self.cloud_search_connection.search(search_request)
27
- ids = res.hits.collect{|h| h["id"]}
28
- self.cloud_search_rails_scope(ids)
61
+ protected
62
+
63
+ # perform a query to CloudSearch and get a response
64
+ def cloud_search_response(query, opts)
65
+ self.cloud_search_connection.search(
66
+ self.cloud_search_request(query, opts)
67
+ )
68
+ end
69
+
70
+ # generate a request to CloudSearch
71
+ def cloud_search_request(query, opts)
72
+ AWSCloudSearch::SearchRequest.new.tap do |req|
73
+ if query.nil?
74
+ req.bq = "type:'#{self.base_class.name}'"
75
+ else
76
+ req.bq = "(and '#{query}' type:'#{self.base_class.name}')"
77
+ end
78
+ req.size = opts[:per_page]
79
+ req.start = (opts[:page] - 1) * opts[:per_page]
80
+ end
29
81
  end
30
82
 
31
83
  end
@@ -8,10 +8,13 @@ describe CloudSearchRails::Index do
8
8
 
9
9
  conn.create_table(:mock_index_classes, :force => true) do |t|
10
10
  t.string(:name)
11
+ t.timestamps
11
12
  end
12
13
 
13
14
  conn.create_table(:mock_index_with_datas, :force => true) do |t|
14
15
  t.string(:name)
16
+ t.string(:type)
17
+ t.timestamps
15
18
  end
16
19
 
17
20
  MockIndexClass = Class.new(ActiveRecord::Base) do
@@ -22,7 +25,7 @@ describe CloudSearchRails::Index do
22
25
 
23
26
  MockIndexWithData = Class.new(ActiveRecord::Base) do
24
27
  indexed_with_cloud_search do |config|
25
- config.cloud_search_domain = "connection-mock"
28
+ config.cloud_search_domain = "mock-index-with-data"
26
29
  end
27
30
  end
28
31
 
@@ -71,7 +74,7 @@ describe CloudSearchRails::Index do
71
74
  end
72
75
  end
73
76
 
74
- context ".cloud_search_delete_document" do
77
+ context ".cloud_search_add_document" do
75
78
 
76
79
  let(:batch_method) do
77
80
  :cloud_search_add_document
@@ -97,6 +100,18 @@ describe CloudSearchRails::Index do
97
100
  it_should_behave_like("batching")
98
101
  end
99
102
 
103
+ context ".cloud_search_domain" do
104
+
105
+ it "should be an inheritable attribute" do
106
+ NewKlass = Class.new(MockIndexWithData)
107
+ NewKlass.cloud_search_domain.should eql(
108
+ MockIndexWithData.cloud_search_domain
109
+ )
110
+ end
111
+
112
+ end
113
+
114
+
100
115
  context ".cloud_search_reindex" do
101
116
 
102
117
  it "should reindex the entire collection" do
@@ -148,6 +163,7 @@ describe CloudSearchRails::Index do
148
163
  doc.expects(:lang=).with("en")
149
164
  doc.expects(:version=).with(t.to_i)
150
165
  doc.expects(:add_field).with("key", "val")
166
+ doc.expects(:add_field).with("type", "MockIndexWithData")
151
167
  AWSCloudSearch::Document.stubs(:new => doc)
152
168
 
153
169
  mock_index_with_data = MockIndexWithData.new
@@ -4,22 +4,28 @@ describe CloudSearchRails::Search do
4
4
 
5
5
  before(:all) do
6
6
 
7
+ conn = ActiveRecord::Base.connection
8
+ conn.create_table(:mock_classes, :force => true) do |t|
9
+ t.string("name")
10
+ t.timestamps
11
+ end
12
+
7
13
  MockClass = Class.new(ActiveRecord::Base) do
8
14
  indexed_with_cloud_search do |config|
9
15
  config.cloud_search_domain = "mock-class"
10
16
  end
17
+
18
+ named_scope :name_like, lambda{|n|
19
+ {:conditions => ["name LIKE ?", n]}
20
+ }
21
+
11
22
  end
12
23
 
13
24
  end
14
25
 
15
26
  context "#cloud_search" do
16
27
 
17
- it "should proxy its search request to cloud_search and return
18
- an Arel-like object" do
19
-
20
- search_request = AWSCloudSearch::SearchRequest.new
21
- search_request.expects(:q=).with("my query")
22
-
28
+ before(:each) do
23
29
  AWSCloudSearch::SearchRequest.stubs(:new => search_request)
24
30
 
25
31
  MockClass.cloud_search_connection
@@ -28,15 +34,91 @@ describe CloudSearchRails::Search do
28
34
  .returns(stub({
29
35
  :hits => [
30
36
  {"id" => 1},
31
- {"id" => 2}]
37
+ {"id" => 2}
38
+ ],
39
+ :found => 300,
40
+ :start => 0
32
41
  }))
42
+ end
43
+
44
+ let(:search_request) do
45
+ search_request = AWSCloudSearch::SearchRequest.new
46
+ search_request.expects(:bq=).with("(and 'my query' type:'MockClass')")
47
+ search_request
48
+ end
49
+
50
+ it "should proxy its search request to cloud_search and return
51
+ an Arel-like object" do
52
+
33
53
  proxy = MockClass.cloud_search("my query")
34
54
  proxy.proxy_options[:conditions].should eql(
35
55
  ["mock_classes.id IN (?)", [1, 2]]
36
56
  )
57
+ end
58
+
59
+ it "should be chainable, maintaining its meta_data" do
60
+ proxy = MockClass.cloud_search("my query").name_like("name")
61
+ proxy.current_page.should eql(1)
62
+ proxy.offset.should eql(0)
63
+ end
64
+
65
+ context "#current_page" do
66
+
67
+ it "should default to 1" do
68
+ proxy = MockClass.cloud_search("my query")
69
+ proxy.current_page.should eql(1)
70
+ end
71
+
72
+ it "should be able to be set" do
73
+ search_request.expects(:start=).with(80)
74
+ proxy = MockClass.cloud_search("my query", :page => 5)
75
+ proxy.current_page.should eql(5)
76
+ end
77
+
78
+ end
79
+
80
+ context "#offset" do
81
+
82
+ it "should be able to compute its offset" do
83
+ proxy = MockClass.cloud_search("my query", :page => 5)
84
+ proxy.offset.should eql(80)
85
+ end
86
+
87
+ end
88
+
89
+ context "#per_page" do
90
+
91
+ it "should default to 20" do
92
+ proxy = MockClass.cloud_search("my query")
93
+ proxy.per_page.should eql(20)
94
+ end
95
+
96
+ it "should be able to be set" do
97
+ search_request.expects(:size=).with(50)
98
+ proxy = MockClass.cloud_search("my query", :per_page => 50)
99
+ proxy.per_page.should eql(50)
100
+ end
37
101
 
38
102
  end
39
103
 
104
+ context "#total_entries" do
105
+
106
+ it "should get it from its search_response" do
107
+ proxy = MockClass.cloud_search("my query")
108
+ proxy.total_entries.should eql(300)
109
+ end
110
+
111
+ end
112
+
113
+ context "#total_pages" do
114
+
115
+ it "should be the ceiling of its total_entries divided
116
+ by per_page" do
117
+ proxy = MockClass.cloud_search("my query", :per_page => 7)
118
+ proxy.total_pages.should eql(43)
119
+ end
120
+
121
+ end
40
122
  end
41
123
 
42
124
  end
@@ -3,6 +3,7 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
3
  require 'rspec'
4
4
  require 'cloud_search_rails'
5
5
  require 'active_record'
6
+ require 'mocha'
6
7
 
7
8
  require 'ruby-debug'
8
9
  Debugger.start
@@ -18,6 +19,8 @@ ActiveRecord::Base.establish_connection({
18
19
 
19
20
  CloudSearchRails.activate_active_record!
20
21
 
22
+ Mocha::Configuration.prevent(:stubbing_non_existent_method)
23
+
21
24
  RSpec.configure do |config|
22
25
  config.mock_with :mocha
23
26
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloud_search_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
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-04-28 00:00:00.000000000 Z
12
+ date: 2012-05-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: aws_cloud_search
16
- requirement: &2165846820 !ruby/object:Gem::Requirement
16
+ requirement: &2177103240 !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: *2165846820
24
+ version_requirements: *2177103240
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rails
27
- requirement: &2165845900 !ruby/object:Gem::Requirement
27
+ requirement: &2177102720 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '2.3'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2165845900
35
+ version_requirements: *2177102720
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: bundler
38
- requirement: &2165844560 !ruby/object:Gem::Requirement
38
+ requirement: &2177101980 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 1.0.0
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *2165844560
46
+ version_requirements: *2177101980
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: guard-rspec
49
- requirement: &2165843160 !ruby/object:Gem::Requirement
49
+ requirement: &2177101120 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *2165843160
57
+ version_requirements: *2177101120
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: jeweler
60
- requirement: &2165842040 !ruby/object:Gem::Requirement
60
+ requirement: &2177100480 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 1.8.3
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *2165842040
68
+ version_requirements: *2177100480
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: mocha
71
- requirement: &2165840700 !ruby/object:Gem::Requirement
71
+ requirement: &2177099660 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *2165840700
79
+ version_requirements: *2177099660
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rdoc
82
- requirement: &2165839680 !ruby/object:Gem::Requirement
82
+ requirement: &2177098540 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ~>
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '3.12'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *2165839680
90
+ version_requirements: *2177098540
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rspec
93
- requirement: &2165838940 !ruby/object:Gem::Requirement
93
+ requirement: &2177097920 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ~>
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: 2.8.0
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *2165838940
101
+ version_requirements: *2177097920
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: ruby-debug19
104
- requirement: &2165838320 !ruby/object:Gem::Requirement
104
+ requirement: &2177097340 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: '0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *2165838320
112
+ version_requirements: *2177097340
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: simplecov
115
- requirement: &2165837580 !ruby/object:Gem::Requirement
115
+ requirement: &2177096780 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ! '>='
@@ -120,10 +120,10 @@ dependencies:
120
120
  version: '0'
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *2165837580
123
+ version_requirements: *2177096780
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: sqlite3
126
- requirement: &2165836960 !ruby/object:Gem::Requirement
126
+ requirement: &2177096280 !ruby/object:Gem::Requirement
127
127
  none: false
128
128
  requirements:
129
129
  - - ! '>='
@@ -131,10 +131,10 @@ dependencies:
131
131
  version: '0'
132
132
  type: :development
133
133
  prerelease: false
134
- version_requirements: *2165836960
134
+ version_requirements: *2177096280
135
135
  - !ruby/object:Gem::Dependency
136
136
  name: yard
137
- requirement: &2165836320 !ruby/object:Gem::Requirement
137
+ requirement: &2177095740 !ruby/object:Gem::Requirement
138
138
  none: false
139
139
  requirements:
140
140
  - - ~>
@@ -142,7 +142,7 @@ dependencies:
142
142
  version: '0.7'
143
143
  type: :development
144
144
  prerelease: false
145
- version_requirements: *2165836320
145
+ version_requirements: *2177095740
146
146
  description: Rails integration for CloudSearch
147
147
  email: dan.langevin@lifebooker.com
148
148
  executables: []
@@ -188,7 +188,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
188
188
  version: '0'
189
189
  segments:
190
190
  - 0
191
- hash: -3038165031770199580
191
+ hash: -2698562838851711787
192
192
  required_rubygems_version: !ruby/object:Gem::Requirement
193
193
  none: false
194
194
  requirements: