cloud_search_rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format nested
3
+ --backtrace
data/Gemfile ADDED
@@ -0,0 +1,23 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ gem "aws_cloud_search"
7
+ gem "rails", "~> 2.3"
8
+
9
+
10
+ # Add dependencies to develop your gem here.
11
+ # Include everything needed to run rake, tests, features, etc.
12
+ group :development do
13
+ gem "bundler", "~> 1.0.0"
14
+ gem "guard-rspec"
15
+ gem "jeweler", "~> 1.8.3"
16
+ gem "mocha"
17
+ gem "rdoc", "~> 3.12"
18
+ gem "rspec", "~> 2.8.0"
19
+ gem "ruby-debug19", :require => "ruby-debug"
20
+ gem "simplecov"
21
+ gem "sqlite3"
22
+ gem "yard", "~> 0.7"
23
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,95 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ actionmailer (2.3.14)
5
+ actionpack (= 2.3.14)
6
+ actionpack (2.3.14)
7
+ activesupport (= 2.3.14)
8
+ rack (~> 1.1.0)
9
+ activerecord (2.3.14)
10
+ activesupport (= 2.3.14)
11
+ activeresource (2.3.14)
12
+ activesupport (= 2.3.14)
13
+ activesupport (2.3.14)
14
+ archive-tar-minitar (0.5.2)
15
+ aws_cloud_search (0.0.1)
16
+ faraday_middleware (>= 0.8.0)
17
+ columnize (0.3.6)
18
+ diff-lcs (1.1.3)
19
+ faraday (0.8.0)
20
+ multipart-post (~> 1.1)
21
+ faraday_middleware (0.8.7)
22
+ faraday (>= 0.7.4, < 0.9)
23
+ ffi (1.0.11)
24
+ git (1.2.5)
25
+ guard (1.0.1)
26
+ ffi (>= 0.5.0)
27
+ thor (~> 0.14.6)
28
+ guard-rspec (0.7.0)
29
+ guard (>= 0.10.0)
30
+ jeweler (1.8.3)
31
+ bundler (~> 1.0)
32
+ git (>= 1.2.5)
33
+ rake
34
+ rdoc
35
+ json (1.6.6)
36
+ linecache19 (0.5.12)
37
+ ruby_core_source (>= 0.1.4)
38
+ metaclass (0.0.1)
39
+ mocha (0.10.5)
40
+ metaclass (~> 0.0.1)
41
+ multi_json (1.3.2)
42
+ multipart-post (1.1.5)
43
+ rack (1.1.3)
44
+ rails (2.3.14)
45
+ actionmailer (= 2.3.14)
46
+ actionpack (= 2.3.14)
47
+ activerecord (= 2.3.14)
48
+ activeresource (= 2.3.14)
49
+ activesupport (= 2.3.14)
50
+ rake (>= 0.8.3)
51
+ rake (0.9.2.2)
52
+ rdoc (3.12)
53
+ json (~> 1.4)
54
+ rspec (2.8.0)
55
+ rspec-core (~> 2.8.0)
56
+ rspec-expectations (~> 2.8.0)
57
+ rspec-mocks (~> 2.8.0)
58
+ rspec-core (2.8.0)
59
+ rspec-expectations (2.8.0)
60
+ diff-lcs (~> 1.1.2)
61
+ rspec-mocks (2.8.0)
62
+ ruby-debug-base19 (0.11.25)
63
+ columnize (>= 0.3.1)
64
+ linecache19 (>= 0.5.11)
65
+ ruby_core_source (>= 0.1.4)
66
+ ruby-debug19 (0.11.6)
67
+ columnize (>= 0.3.1)
68
+ linecache19 (>= 0.5.11)
69
+ ruby-debug-base19 (>= 0.11.19)
70
+ ruby_core_source (0.1.5)
71
+ archive-tar-minitar (>= 0.5.2)
72
+ simplecov (0.6.2)
73
+ multi_json (~> 1.3)
74
+ simplecov-html (~> 0.5.3)
75
+ simplecov-html (0.5.3)
76
+ sqlite3 (1.3.5)
77
+ thor (0.14.6)
78
+ yard (0.7.5)
79
+
80
+ PLATFORMS
81
+ ruby
82
+
83
+ DEPENDENCIES
84
+ aws_cloud_search
85
+ bundler (~> 1.0.0)
86
+ guard-rspec
87
+ jeweler (~> 1.8.3)
88
+ mocha
89
+ rails (~> 2.3)
90
+ rdoc (~> 3.12)
91
+ rspec (~> 2.8.0)
92
+ ruby-debug19
93
+ simplecov
94
+ sqlite3
95
+ yard (~> 0.7)
data/Guardfile ADDED
@@ -0,0 +1,19 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', :version => 2 do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+ # Capybara request specs
17
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
18
+ end
19
+
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Dan Langevin
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = cloud_search_rails
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to cloud_search_rails
6
+
7
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
8
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
9
+ * Fork the project.
10
+ * Start a feature/bugfix branch.
11
+ * Commit and push until you are happy with your contribution.
12
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2012 Dan Langevin. See LICENSE.txt for
18
+ further details.
19
+
data/Rakefile ADDED
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "cloud_search_rails"
18
+ gem.homepage = "http://github.com/dlangevin/cloud_search_rails"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Rails integration for CloudSearch}
21
+ gem.description = %Q{Rails integration for CloudSearch}
22
+ gem.email = "dan.langevin@lifebooker.com"
23
+ gem.authors = ["Dan Langevin"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.rcov = true
37
+ end
38
+
39
+ task :default => :spec
40
+
41
+ require 'yard'
42
+ YARD::Rake::YardocTask.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,94 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "cloud_search_rails"
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Dan Langevin"]
12
+ s.date = "2012-04-28"
13
+ s.description = "Rails integration for CloudSearch"
14
+ s.email = "dan.langevin@lifebooker.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "Guardfile",
25
+ "LICENSE.txt",
26
+ "README.rdoc",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "cloud_search_rails.gemspec",
30
+ "lib/cloud_search_rails.rb",
31
+ "lib/cloud_search_rails/connection.rb",
32
+ "lib/cloud_search_rails/exceptions.rb",
33
+ "lib/cloud_search_rails/index.rb",
34
+ "lib/cloud_search_rails/railtie.rb",
35
+ "lib/cloud_search_rails/search.rb",
36
+ "spec/acceptance/aws_spec.rb",
37
+ "spec/cloud_search_rails/connection_spec.rb",
38
+ "spec/cloud_search_rails/index_spec.rb",
39
+ "spec/cloud_search_rails/search_spec.rb",
40
+ "spec/cloud_search_rails_spec.rb",
41
+ "spec/spec_helper.rb"
42
+ ]
43
+ s.homepage = "http://github.com/dlangevin/cloud_search_rails"
44
+ s.licenses = ["MIT"]
45
+ s.require_paths = ["lib"]
46
+ s.rubygems_version = "1.8.11"
47
+ s.summary = "Rails integration for CloudSearch"
48
+
49
+ if s.respond_to? :specification_version then
50
+ s.specification_version = 3
51
+
52
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
53
+ s.add_runtime_dependency(%q<aws_cloud_search>, [">= 0"])
54
+ s.add_runtime_dependency(%q<rails>, ["~> 2.3"])
55
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
56
+ s.add_development_dependency(%q<guard-rspec>, [">= 0"])
57
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
58
+ s.add_development_dependency(%q<mocha>, [">= 0"])
59
+ s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
60
+ s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
61
+ s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
62
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
63
+ s.add_development_dependency(%q<sqlite3>, [">= 0"])
64
+ s.add_development_dependency(%q<yard>, ["~> 0.7"])
65
+ else
66
+ s.add_dependency(%q<aws_cloud_search>, [">= 0"])
67
+ s.add_dependency(%q<rails>, ["~> 2.3"])
68
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
69
+ s.add_dependency(%q<guard-rspec>, [">= 0"])
70
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
71
+ s.add_dependency(%q<mocha>, [">= 0"])
72
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
73
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
74
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
75
+ s.add_dependency(%q<simplecov>, [">= 0"])
76
+ s.add_dependency(%q<sqlite3>, [">= 0"])
77
+ s.add_dependency(%q<yard>, ["~> 0.7"])
78
+ end
79
+ else
80
+ s.add_dependency(%q<aws_cloud_search>, [">= 0"])
81
+ s.add_dependency(%q<rails>, ["~> 2.3"])
82
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
83
+ s.add_dependency(%q<guard-rspec>, [">= 0"])
84
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
85
+ s.add_dependency(%q<mocha>, [">= 0"])
86
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
87
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
88
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
89
+ s.add_dependency(%q<simplecov>, [">= 0"])
90
+ s.add_dependency(%q<sqlite3>, [">= 0"])
91
+ s.add_dependency(%q<yard>, ["~> 0.7"])
92
+ end
93
+ end
94
+
@@ -0,0 +1,24 @@
1
+ module CloudSearchRails
2
+ module Connection
3
+
4
+ def self.included(klass)
5
+ klass.send(:extend, ClassMethods)
6
+ klass.class_eval do
7
+ class_inheritable_accessor :cloud_search_domain
8
+ end
9
+ end
10
+
11
+ module ClassMethods
12
+
13
+ # accessor for the cloud search connection
14
+ def cloud_search_connection
15
+ @cloud_search_connection ||= begin
16
+ CloudSearchRails.connection(
17
+ self.cloud_search_domain
18
+ )
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ module CloudSearchRails
2
+ class MissingSearchDomain < Exception; end;
3
+ end
@@ -0,0 +1,110 @@
1
+ module CloudSearchRails
2
+ module Index
3
+
4
+ def self.included(klass)
5
+ klass.send(:include, InstanceMethods)
6
+ klass.send(:extend, ClassMethods)
7
+ klass.class_eval do
8
+ cattr_accessor :in_cloud_search_batch_documents
9
+ self.in_cloud_search_batch_documents = false
10
+
11
+ # set up our callbacks
12
+ after_save(:add_to_cloud_search)
13
+ after_destroy(:delete_from_cloud_search)
14
+ end
15
+ end
16
+
17
+ module InstanceMethods
18
+
19
+ # add ourself as a document to CloudSearch
20
+ def add_to_cloud_search
21
+ self.class.cloud_search_add_document(
22
+ self.cloud_search_document
23
+ )
24
+ end
25
+
26
+ # empty implementation - re-implement
27
+ # or we might end up doing some meta-programming here
28
+ def cloud_search_data
29
+ {}
30
+ end
31
+
32
+ # wrapper for a fully formed AWSCloudSearch::Document
33
+ def cloud_search_document
34
+ AWSCloudSearch::Document.new.tap do |d|
35
+ d.id = self.id
36
+ d.lang = "en"
37
+ d.version = self.updated_at.to_i
38
+ self.cloud_search_data.each_pair do |k,v|
39
+ d.add_field(k.to_s, v.to_s)
40
+ end
41
+ end
42
+ end
43
+
44
+ # add ourself as a document to CloudSearch
45
+ def delete_from_cloud_search
46
+ self.class.cloud_search_delete_document(
47
+ self.cloud_search_document
48
+ )
49
+ end
50
+
51
+ end
52
+
53
+ module ClassMethods
54
+
55
+ # class method to add documents
56
+ def cloud_search_add_document(doc)
57
+ self.cloud_search_batcher_command(:add_document, doc)
58
+ end
59
+
60
+ # class method to add documents
61
+ def cloud_search_delete_document(doc)
62
+ self.cloud_search_batcher_command(:delete_document, doc)
63
+ end
64
+
65
+ # perform all add/delete operations within a buffered
66
+ # DocumentBatcher
67
+ def cloud_search_batch_documents(&block)
68
+ begin
69
+ self.in_cloud_search_batch_documents = true
70
+ yield
71
+ # final flush for any left over documents
72
+ self.cloud_search_document_batcher.flush
73
+ ensure
74
+ self.in_cloud_search_batch_documents = false
75
+ end
76
+ end
77
+
78
+ # reindex the entire collection
79
+ def cloud_search_reindex(*args)
80
+ self.cloud_search_batch_documents do
81
+ self.find_each(*args) do |record|
82
+ record.add_to_cloud_search
83
+ end
84
+ end
85
+ end
86
+
87
+ # new instance of AWSCloudSearch::DocumentBatcher
88
+ def cloud_search_document_batcher
89
+ @cloud_search_document_batcher ||= begin
90
+ self.cloud_search_connection.new_batcher
91
+ end
92
+ end
93
+
94
+ protected
95
+ # send a command to the batcher and then conditionally flush
96
+ # depending on whether we are in a cloud_search_batch_documents
97
+ # block
98
+ def cloud_search_batcher_command(command, doc)
99
+ # send the command to our batcher
100
+ self.cloud_search_document_batcher.send(command, doc)
101
+
102
+ # if we are not in a batch_documents block, flush immediately
103
+ unless self.in_cloud_search_batch_documents
104
+ self.cloud_search_document_batcher.flush
105
+ end
106
+ end
107
+ end
108
+
109
+ end
110
+ end
@@ -0,0 +1,9 @@
1
+ module CloudSearchRails
2
+ class Railtie < Rails::Railtie
3
+
4
+ initializer "cloud_search_rails.activate" do
5
+ CloudSearchRails.activate_active_record!
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,34 @@
1
+ module CloudSearchRails
2
+
3
+ module Search
4
+ def self.included(klass)
5
+ klass.send(:extend, ClassMethods)
6
+ klass.class_eval do
7
+ named_scope :cloud_search_rails_scope, lambda{|*ids|
8
+ {
9
+ :conditions => [
10
+ "#{self.table_name}.#{self.primary_key} IN (?)", ids.flatten
11
+ ]
12
+ }
13
+ }
14
+ end
15
+ end
16
+
17
+ module ClassMethods
18
+
19
+ # 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
25
+
26
+ res = self.cloud_search_connection.search(search_request)
27
+ ids = res.hits.collect{|h| h["id"]}
28
+ self.cloud_search_rails_scope(ids)
29
+ end
30
+
31
+ end
32
+ end
33
+
34
+ end
@@ -0,0 +1,44 @@
1
+ require 'aws_cloud_search'
2
+ require 'cloud_search_rails/connection'
3
+ require 'cloud_search_rails/exceptions'
4
+ require 'cloud_search_rails/index'
5
+ require 'cloud_search_rails/search'
6
+
7
+ module CloudSearchRails
8
+
9
+ def self.connection(domain = "default")
10
+ @connections ||= {}
11
+ @connections[domain] ||= AWSCloudSearch::CloudSearch.new(domain)
12
+ end
13
+
14
+ # activate for ActiveRecord
15
+ def self.activate_active_record!
16
+ ::ActiveRecord::Base.send(:extend, CloudSearchRails::ActiveRecord)
17
+ end
18
+
19
+ module ActiveRecord
20
+
21
+ # activation method for an AR class
22
+ def indexed_with_cloud_search(&block)
23
+ mods = [
24
+ CloudSearchRails::Connection,
25
+ CloudSearchRails::Index,
26
+ CloudSearchRails::Search
27
+ ]
28
+ mods.each do |mod|
29
+ unless self.included_modules.include?(mod)
30
+ self.send(:include, mod)
31
+ end
32
+ end
33
+ # config block
34
+ yield(self) if block_given?
35
+
36
+ # ensure config is all set
37
+ unless self.cloud_search_domain.present?
38
+ raise CloudSearchRails::MissingSearchDomain.new
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe "AWS" do
4
+
5
+ before(:all) do
6
+
7
+ conn = ActiveRecord::Base.connection
8
+ conn.create_table(:clients, :force => true) do |t|
9
+ t.string(:first_name)
10
+ t.string(:last_name)
11
+ t.string(:email)
12
+ t.timestamps
13
+ end
14
+
15
+ Client = Class.new(ActiveRecord::Base) do
16
+ indexed_with_cloud_search do |config|
17
+ config.cloud_search_domain = "client-4wwi2n4ghrnro46w2adiw2temy"
18
+ end
19
+
20
+ def cloud_search_data
21
+ self.attributes
22
+ end
23
+
24
+ end
25
+
26
+ Client.create(
27
+ :first_name => "Dan",
28
+ :last_name => "Langevin",
29
+ :email => "test@test.com"
30
+ )
31
+ end
32
+
33
+ after(:all) do
34
+ Client.all.each(&:destroy)
35
+ end
36
+
37
+ it "should be able to index and search records" do
38
+
39
+ Client.cloud_search_reindex
40
+ c = Client.cloud_search("Dan Langevin").first
41
+ c.should be_instance_of(Client)
42
+
43
+ end
44
+
45
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe CloudSearchRails::Connection do
4
+
5
+ before(:each) do
6
+
7
+ ConnectionMock = Class.new(ActiveRecord::Base) do
8
+ indexed_with_cloud_search do |config|
9
+ config.cloud_search_domain = "connection-mock"
10
+ end
11
+ end
12
+
13
+ end
14
+
15
+ context ".cloud_search_connection" do
16
+
17
+ it "should get a namespaced connection" do
18
+ ConnectionMock.stubs(:cloud_search_domain => "connection-mock")
19
+ CloudSearchRails.expects(:connection).with("connection-mock")
20
+ ConnectionMock.cloud_search_connection
21
+ end
22
+
23
+ end
24
+
25
+ context ".cloud_search_domain" do
26
+
27
+ it "should provide a setter and getter" do
28
+ ConnectionMock.cloud_search_domain = "123"
29
+ ConnectionMock.cloud_search_domain.should eql "123"
30
+
31
+ ConnectionMock2 = Class.new(ConnectionMock)
32
+ ConnectionMock2.cloud_search_domain.should eql "123"
33
+ end
34
+
35
+ it "should raise an error if cloud_search_domain is not defined" do
36
+
37
+ lambda{
38
+ ErrorMock = Class.new(ActiveRecord::Base) do
39
+ indexed_with_cloud_search
40
+ end
41
+ }.should raise_error(CloudSearchRails::MissingSearchDomain)
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,181 @@
1
+ require 'spec_helper'
2
+
3
+ describe CloudSearchRails::Index do
4
+
5
+ before(:all) do
6
+
7
+ conn = ActiveRecord::Base.connection
8
+
9
+ conn.create_table(:mock_index_classes, :force => true) do |t|
10
+ t.string(:name)
11
+ end
12
+
13
+ conn.create_table(:mock_index_with_datas, :force => true) do |t|
14
+ t.string(:name)
15
+ end
16
+
17
+ MockIndexClass = Class.new(ActiveRecord::Base) do
18
+ indexed_with_cloud_search do |config|
19
+ config.cloud_search_domain = "connection-mock"
20
+ end
21
+ end
22
+
23
+ MockIndexWithData = Class.new(ActiveRecord::Base) do
24
+ indexed_with_cloud_search do |config|
25
+ config.cloud_search_domain = "connection-mock"
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ shared_examples_for "batching" do
32
+
33
+ it "should add a document to its batch, flushing each time" do
34
+
35
+ doc = AWSCloudSearch::Document.new
36
+ doc2 = AWSCloudSearch::Document.new
37
+
38
+ batcher = AWSCloudSearch::DocumentBatcher.new(stub)
39
+ batcher.expects(document_method).with(doc)
40
+ batcher.expects(document_method).with(doc2)
41
+ batcher.expects(:flush).twice
42
+
43
+ MockIndexWithData.stubs(:cloud_search_document_batcher => batcher)
44
+
45
+ MockIndexWithData.send(batch_method, doc)
46
+ MockIndexWithData.send(batch_method, doc2)
47
+
48
+ end
49
+
50
+ it "should add a document to its batch flushing only at the end
51
+ when within a cloud_search_batch_documents block" do
52
+
53
+
54
+ doc = AWSCloudSearch::Document.new
55
+ doc2 = AWSCloudSearch::Document.new
56
+
57
+ batcher = AWSCloudSearch::DocumentBatcher.new(stub)
58
+ batcher.expects(document_method).with(doc)
59
+ batcher.expects(document_method).with(doc2)
60
+
61
+ # exactly one
62
+ batcher.expects(:flush).once
63
+
64
+ MockIndexWithData.stubs(:cloud_search_document_batcher => batcher)
65
+
66
+ MockIndexWithData.cloud_search_batch_documents do
67
+ MockIndexWithData.send(batch_method, doc)
68
+ MockIndexWithData.send(batch_method, doc2)
69
+ end
70
+
71
+ end
72
+ end
73
+
74
+ context ".cloud_search_delete_document" do
75
+
76
+ let(:batch_method) do
77
+ :cloud_search_add_document
78
+ end
79
+
80
+ let(:document_method) do
81
+ :add_document
82
+ end
83
+
84
+ it_should_behave_like("batching")
85
+ end
86
+
87
+ context ".cloud_search_delete_document" do
88
+
89
+ let(:batch_method) do
90
+ :cloud_search_delete_document
91
+ end
92
+
93
+ let(:document_method) do
94
+ :delete_document
95
+ end
96
+
97
+ it_should_behave_like("batching")
98
+ end
99
+
100
+ context ".cloud_search_reindex" do
101
+
102
+ it "should reindex the entire collection" do
103
+ mock_index_with_data = MockIndexWithData.new
104
+ mock_index_with_data.expects(:add_to_cloud_search)
105
+
106
+ MockIndexWithData.cloud_search_document_batcher.expects(:flush)
107
+ MockIndexWithData.expects(:find_each)
108
+ .with(:conditions => ["x = y"])
109
+ .yields(mock_index_with_data)
110
+
111
+ MockIndexWithData.cloud_search_reindex(:conditions => ["x = y"])
112
+ end
113
+
114
+ end
115
+
116
+
117
+ context "#add_to_cloud_search" do
118
+
119
+ it "should add a document to CloudSearch" do
120
+ doc = AWSCloudSearch::Document.new
121
+
122
+ mock_index_with_data = MockIndexWithData.new
123
+ mock_index_with_data.stubs(:cloud_search_document => doc)
124
+
125
+ MockIndexWithData.expects(:cloud_search_add_document).with(doc)
126
+
127
+ # call add to cloud_search
128
+ mock_index_with_data.add_to_cloud_search
129
+ end
130
+ end
131
+
132
+ context "#cloud_search_data" do
133
+
134
+ it "should define an empty cloud_search_data method" do
135
+ MockIndexClass.new.cloud_search_data.should eql({})
136
+ end
137
+
138
+ end
139
+
140
+ context "#cloud_search_document" do
141
+
142
+ it "should provide a wrapper for the document that is indexed " do
143
+
144
+ t = Time.now
145
+
146
+ doc = AWSCloudSearch::Document.new
147
+ doc.expects(:id=).with(8989)
148
+ doc.expects(:lang=).with("en")
149
+ doc.expects(:version=).with(t.to_i)
150
+ doc.expects(:add_field).with("key", "val")
151
+ AWSCloudSearch::Document.stubs(:new => doc)
152
+
153
+ mock_index_with_data = MockIndexWithData.new
154
+ mock_index_with_data.stubs(
155
+ :cloud_search_data => {:key => "val"},
156
+ :id => 8989,
157
+ :updated_at => t.to_i
158
+ )
159
+ mock_index_with_data.cloud_search_document.should eql(doc)
160
+ end
161
+
162
+ end
163
+
164
+ context "#delete_from_cloud_search" do
165
+
166
+ it "should remvoe a document from CloudSearch" do
167
+ doc = AWSCloudSearch::Document.new
168
+
169
+ mock_index_with_data = MockIndexWithData.new
170
+ mock_index_with_data.stubs(:cloud_search_document => doc)
171
+
172
+ MockIndexWithData.expects(:cloud_search_delete_document).with(doc)
173
+
174
+ # call add to cloud_search
175
+ mock_index_with_data.delete_from_cloud_search
176
+ end
177
+
178
+ end
179
+
180
+
181
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe CloudSearchRails::Search do
4
+
5
+ before(:all) do
6
+
7
+ MockClass = Class.new(ActiveRecord::Base) do
8
+ indexed_with_cloud_search do |config|
9
+ config.cloud_search_domain = "mock-class"
10
+ end
11
+ end
12
+
13
+ end
14
+
15
+ context "#cloud_search" do
16
+
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
+
23
+ AWSCloudSearch::SearchRequest.stubs(:new => search_request)
24
+
25
+ MockClass.cloud_search_connection
26
+ .expects(:search)
27
+ .with(search_request)
28
+ .returns(stub({
29
+ :hits => [
30
+ {"id" => 1},
31
+ {"id" => 2}]
32
+ }))
33
+ proxy = MockClass.cloud_search("my query")
34
+ proxy.proxy_options[:conditions].should eql(
35
+ ["mock_classes.id IN (?)", [1, 2]]
36
+ )
37
+
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,45 @@
1
+ require "spec_helper"
2
+
3
+ describe CloudSearchRails do
4
+
5
+ context "#connection" do
6
+
7
+ it "should get an instance of connection" do
8
+ CloudSearchRails.connection.should be_instance_of(
9
+ AWSCloudSearch::CloudSearch
10
+ )
11
+ end
12
+
13
+ it "should be able to configure its connection's domain" do
14
+ AWSCloudSearch::CloudSearch.expects(:new).with("domain")
15
+ CloudSearchRails.connection("domain")
16
+ end
17
+ end
18
+
19
+ context "#indexed_with_cloud_search" do
20
+
21
+ it "should include the appropriate modules" do
22
+
23
+ Indexed = Class.new(ActiveRecord::Base)
24
+
25
+ Indexed.expects(:after_save).with(:add_to_cloud_search)
26
+ Indexed.expects(:after_destroy).with(:delete_from_cloud_search)
27
+
28
+ Indexed.class_eval do
29
+ indexed_with_cloud_search do |config|
30
+ config.cloud_search_domain = "connection-mock"
31
+ end
32
+ end
33
+
34
+ mods = [
35
+ CloudSearchRails::Connection,
36
+ CloudSearchRails::Index,
37
+ CloudSearchRails::Search
38
+ ]
39
+ mods.each do |mod|
40
+ Indexed.included_modules.should include mod
41
+ end
42
+ end
43
+ end
44
+
45
+ end
@@ -0,0 +1,23 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'cloud_search_rails'
5
+ require 'active_record'
6
+
7
+ require 'ruby-debug'
8
+ Debugger.start
9
+
10
+ # Requires supporting files with custom matchers and macros, etc,
11
+ # in ./support/ and its subdirectories.
12
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
13
+
14
+ ActiveRecord::Base.establish_connection({
15
+ "adapter" => "sqlite3",
16
+ "database" => "/tmp/cloud_search_rails_test.sqlite"
17
+ })
18
+
19
+ CloudSearchRails.activate_active_record!
20
+
21
+ RSpec.configure do |config|
22
+ config.mock_with :mocha
23
+ end
metadata ADDED
@@ -0,0 +1,204 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cloud_search_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dan Langevin
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: aws_cloud_search
16
+ requirement: &2165846820 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2165846820
25
+ - !ruby/object:Gem::Dependency
26
+ name: rails
27
+ requirement: &2165845900 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '2.3'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *2165845900
36
+ - !ruby/object:Gem::Dependency
37
+ name: bundler
38
+ requirement: &2165844560 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.0.0
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2165844560
47
+ - !ruby/object:Gem::Dependency
48
+ name: guard-rspec
49
+ requirement: &2165843160 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *2165843160
58
+ - !ruby/object:Gem::Dependency
59
+ name: jeweler
60
+ requirement: &2165842040 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 1.8.3
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *2165842040
69
+ - !ruby/object:Gem::Dependency
70
+ name: mocha
71
+ requirement: &2165840700 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *2165840700
80
+ - !ruby/object:Gem::Dependency
81
+ name: rdoc
82
+ requirement: &2165839680 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ~>
86
+ - !ruby/object:Gem::Version
87
+ version: '3.12'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *2165839680
91
+ - !ruby/object:Gem::Dependency
92
+ name: rspec
93
+ requirement: &2165838940 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ~>
97
+ - !ruby/object:Gem::Version
98
+ version: 2.8.0
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *2165838940
102
+ - !ruby/object:Gem::Dependency
103
+ name: ruby-debug19
104
+ requirement: &2165838320 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: *2165838320
113
+ - !ruby/object:Gem::Dependency
114
+ name: simplecov
115
+ requirement: &2165837580 !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ type: :development
122
+ prerelease: false
123
+ version_requirements: *2165837580
124
+ - !ruby/object:Gem::Dependency
125
+ name: sqlite3
126
+ requirement: &2165836960 !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ! '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: *2165836960
135
+ - !ruby/object:Gem::Dependency
136
+ name: yard
137
+ requirement: &2165836320 !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ~>
141
+ - !ruby/object:Gem::Version
142
+ version: '0.7'
143
+ type: :development
144
+ prerelease: false
145
+ version_requirements: *2165836320
146
+ description: Rails integration for CloudSearch
147
+ email: dan.langevin@lifebooker.com
148
+ executables: []
149
+ extensions: []
150
+ extra_rdoc_files:
151
+ - LICENSE.txt
152
+ - README.rdoc
153
+ files:
154
+ - .document
155
+ - .rspec
156
+ - Gemfile
157
+ - Gemfile.lock
158
+ - Guardfile
159
+ - LICENSE.txt
160
+ - README.rdoc
161
+ - Rakefile
162
+ - VERSION
163
+ - cloud_search_rails.gemspec
164
+ - lib/cloud_search_rails.rb
165
+ - lib/cloud_search_rails/connection.rb
166
+ - lib/cloud_search_rails/exceptions.rb
167
+ - lib/cloud_search_rails/index.rb
168
+ - lib/cloud_search_rails/railtie.rb
169
+ - lib/cloud_search_rails/search.rb
170
+ - spec/acceptance/aws_spec.rb
171
+ - spec/cloud_search_rails/connection_spec.rb
172
+ - spec/cloud_search_rails/index_spec.rb
173
+ - spec/cloud_search_rails/search_spec.rb
174
+ - spec/cloud_search_rails_spec.rb
175
+ - spec/spec_helper.rb
176
+ homepage: http://github.com/dlangevin/cloud_search_rails
177
+ licenses:
178
+ - MIT
179
+ post_install_message:
180
+ rdoc_options: []
181
+ require_paths:
182
+ - lib
183
+ required_ruby_version: !ruby/object:Gem::Requirement
184
+ none: false
185
+ requirements:
186
+ - - ! '>='
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ segments:
190
+ - 0
191
+ hash: -3038165031770199580
192
+ required_rubygems_version: !ruby/object:Gem::Requirement
193
+ none: false
194
+ requirements:
195
+ - - ! '>='
196
+ - !ruby/object:Gem::Version
197
+ version: '0'
198
+ requirements: []
199
+ rubyforge_project:
200
+ rubygems_version: 1.8.11
201
+ signing_key:
202
+ specification_version: 3
203
+ summary: Rails integration for CloudSearch
204
+ test_files: []