asari 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in asari.gemspec
4
+ gemspec
@@ -0,0 +1,4 @@
1
+ asari
2
+ =====
3
+
4
+ a Ruby wrapper for AWS CloudSearch.
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "asari/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "asari"
7
+ s.version = Asari::VERSION
8
+ s.authors = ["Tommy Morgan"]
9
+ s.email = ["tommy@wellbredgrapefruit.com"]
10
+ s.homepage = "http://github.com/duwanis/asari"
11
+ s.summary = %q{Asari is a Ruby interface for AWS CloudSearch.}
12
+ s.description = %q{Asari s a Ruby interface for AWS CloudSearch}
13
+
14
+ s.rubyforge_project = "asari"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency "rspec"
23
+ # s.add_runtime_dependency "rest-client"
24
+
25
+ s.add_runtime_dependency "httparty"
26
+
27
+ s.add_development_dependency "rspec"
28
+ end
@@ -0,0 +1,151 @@
1
+ require "asari/version"
2
+
3
+ require "asari/exceptions"
4
+
5
+ require "httparty"
6
+
7
+ require "json"
8
+ require "cgi"
9
+
10
+ class Asari
11
+ class << self
12
+ attr_accessor :mode
13
+ @mode = :sandbox
14
+ end
15
+
16
+ attr_writer :api_version
17
+ attr_writer :search_domain
18
+
19
+ def initialize(search_domain=nil)
20
+ @search_domain = search_domain
21
+ end
22
+
23
+ # Public: returns the current search_domain, or raises a
24
+ # MissingSearchDomainException.
25
+ #
26
+ def search_domain
27
+ @search_domain || raise(MissingSearchDomainException.new)
28
+ end
29
+
30
+ # Public: returns the current api_version, or the sensible default of
31
+ # "2011-02-01" (at the time of writing, the current version of the
32
+ # CloudSearch API).
33
+ #
34
+ def api_version
35
+ @api_version || "2011-02-01"
36
+ end
37
+
38
+ # Public: Search for the specified term.
39
+ #
40
+ # Examples:
41
+ #
42
+ # @asari.search("fritters") #=> ["13","28"]
43
+ #
44
+ # Returns: An Array of all document IDs in the system that match the
45
+ # specified search term. If no results are found, an empty Array is
46
+ # returned.
47
+ #
48
+ # Raises: SearchException if there's an issue communicating the request to
49
+ # the server.
50
+ def search(term)
51
+ return [] if self.class.mode == :sandbox
52
+
53
+ url = "http://search-#{search_domain}.us-east-1.cloudsearch.amazonaws.com/#{api_version}/search?q=#{CGI.escape(term)}"
54
+ begin
55
+ response = HTTParty.get(url)
56
+ rescue Exception => e
57
+ ae = Asari::SearchException.new("#{e.class}: #{e.message}")
58
+ ae.set_backtrace e.backtrace
59
+ raise ae
60
+ end
61
+
62
+ unless response.response.code == "200"
63
+ raise Asari::SearchException.new("#{response.response.code}: #{response.response.msg}")
64
+ end
65
+
66
+ response.parsed_response["hits"]["hit"].map { |h| h["id"] }
67
+ end
68
+
69
+ # Public: Add an item to the index with the given ID.
70
+ #
71
+ # id - the ID to associate with this document
72
+ # fields - a hash of the data to associate with this document. This
73
+ # needs to match the search fields defined in your CloudSearch domain.
74
+ #
75
+ # Examples:
76
+ #
77
+ # @asari.update_item("4", { :name => "Party Pooper", :email => ..., ... }) #=> nil
78
+ #
79
+ # Returns: nil if the request is successful.
80
+ #
81
+ # Raises: DocumentUpdateException if there's an issue communicating the
82
+ # request to the server.
83
+ #
84
+ def add_item(id, fields)
85
+ return nil if self.class.mode == :sandbox
86
+ query = { "type" => "add", "id" => id, "version" => 1, "lang" => "en" }
87
+ query["fields"] = fields
88
+ doc_request(query)
89
+ end
90
+
91
+ # Public: Update an item in the index based on its document ID.
92
+ # Note: As of right now, this is the same method call in CloudSearch
93
+ # that's utilized for adding items. This method is here to provide a
94
+ # consistent interface in case that changes.
95
+ #
96
+ # Examples:
97
+ #
98
+ # @asari.update_item("4", { :name => "Party Pooper", :email => ..., ... }) #=> nil
99
+ #
100
+ # Returns: nil if the request is successful.
101
+ #
102
+ # Raises: DocumentUpdateException if there's an issue communicating the
103
+ # request to the server.
104
+ #
105
+ def update_item(id, fields)
106
+ add_item(id, fields)
107
+ end
108
+
109
+ # Public: Remove an item from the index based on its document ID.
110
+ #
111
+ # Examples:
112
+ #
113
+ # @asari.search("fritters") #=> ["13","28"]
114
+ # @asari.remove_item("13") #=> nil
115
+ # @asari.search("fritters") #=> ["28"]
116
+ # @asari.remove_item("13") #=> nil
117
+ #
118
+ # Returns: nil if the request is successful (note that asking the index to
119
+ # delete an item that's not present in the index is still a successful
120
+ # request).
121
+ # Raises: DocumentUpdateException if there's an issue communicating the
122
+ # request to the server.
123
+ def remove_item(id)
124
+ return nil if self.class.mode == :sandbox
125
+
126
+ query = { "type" => "delete", "id" => id, "version" => 2 }
127
+ doc_request query
128
+ end
129
+
130
+ # Internal: helper method: common logic for queries against the doc endpoint.
131
+ #
132
+ def doc_request(query)
133
+ endpoint = "http://doc-#{search_domain}.us-east-1.cloudsearch.amazonaws.com/#{api_version}/documents/batch"
134
+
135
+ options = { :body => [query].to_json, :headers => { "Content-Type" => "application/json"} }
136
+
137
+ begin
138
+ response = HTTParty.post(endpoint, options)
139
+ rescue Exception => e
140
+ ae = Asari::DocumentUpdateException.new("#{e.class}: #{e.message}")
141
+ ae.set_backtrace e.backtrace
142
+ raise ae
143
+ end
144
+
145
+ unless response.response.code == "200"
146
+ raise Asari::DocumentUpdateException.new("#{response.response.code}: #{response.response.msg}")
147
+ end
148
+
149
+ nil
150
+ end
151
+ end
@@ -0,0 +1,114 @@
1
+ class Asari
2
+ # Public: This module should be included in any class inheriting from
3
+ # ActiveRecord::Base that needs to be indexed. Every time this module is
4
+ # included, asari_index *must* be called (see below). Including this module
5
+ # will automatically create before_delete, after_create, and after_update AR
6
+ # callbacks to remove, add, and update items in the CloudSearch index
7
+ # (respectively).
8
+ #
9
+ module ActiveRecord
10
+ def self.included(base)
11
+ base.extend(ClassMethods)
12
+
13
+ base.before_delete :asari_remove_from_index
14
+ base.after_create :asari_add_to_index
15
+ base.after_update :asari_update_in_index
16
+ end
17
+
18
+ def asari_remove_from_index
19
+ self.class.asari_remove_item(self)
20
+ end
21
+
22
+ def asari_add_to_index
23
+ self.class.asari_add_item(self)
24
+ end
25
+
26
+ def asari_update_in_index
27
+ self.class.asari_update_item(self)
28
+ end
29
+
30
+ module ClassMethods
31
+
32
+ # Public: DSL method for adding this model object to the asari search
33
+ # index.
34
+ #
35
+ # This method *must* be called in any object that includes
36
+ # Asari::ActiveRecord, or your methods will be very sad.
37
+ #
38
+ # search_domain - the CloudSearch domain to use for indexing this model.
39
+ # fields - an array of Symbols representing the list of fields that
40
+ # should be included in this index.
41
+ #
42
+ # Examples:
43
+ # class User < ActiveRecord::Base
44
+ # include Asari::ActiveRecord
45
+ #
46
+ # asari_index("my-companies-users-asglkj4rsagkjlh34", [:name, :email])
47
+ #
48
+ def asari_index(search_domain, fields)
49
+ @asari = Asari.new(search_domain)
50
+ @fields = fields
51
+ end
52
+
53
+ # Internal: method for adding a newly created item to the CloudSearch
54
+ # index. Should probably only be called from asari_add_to_index above.
55
+ def asari_add_item(obj)
56
+ data = {}
57
+ @fields.each do |field|
58
+ data[field] = obj.send(field)
59
+ end
60
+ @asari.add_item(obj.send(:id), data)
61
+ rescue Asari::DocumentUpdateException => e
62
+ asari_on_error(e)
63
+ end
64
+
65
+ # Internal: method for updating a freshly edited item to the CloudSearch
66
+ # index. Should probably only be called from asari_update_in_index above.
67
+ def asari_update_item(obj)
68
+ data = {}
69
+ @fields.each do |field|
70
+ data[field] = obj.send(field)
71
+ end
72
+ @asari.update_item(obj.send(:id), data)
73
+ rescue Asari::DocumentUpdateException => e
74
+ asari_on_error(e)
75
+ end
76
+
77
+ # Internal: method for removing a soon-to-be deleted item from the CloudSearch
78
+ # index. Should probably only be called from asari_remove_from_index above.
79
+ def asari_remove_item(obj)
80
+ @asari.remove_item(obj.send(:id))
81
+ rescue Asari::DocumentUpdateException => e
82
+ asari_on_error(e)
83
+ end
84
+
85
+ # Public: method for searching the index for the specified term and
86
+ # returning all model objects that match.
87
+ #
88
+ # Returns: a list of all matching AR model objects, or an empty list if no
89
+ # records are found that match.
90
+ #
91
+ # Raises: an Asari::SearchException error if there are issues
92
+ # communicating with the CloudSearch server.
93
+ def asari_find(term)
94
+ ids = @asari.search(term).map { |id| id.to_i }
95
+ begin
96
+ self.find(*ids)
97
+ rescue ::ActiveRecord::RecordNotFound
98
+ []
99
+ end
100
+ end
101
+
102
+ # Public: method for handling errors from Asari document updates. By
103
+ # default, this method causes all such exceptions (generated by issues
104
+ # from updates, creates, or deletes to the index) to be raised immediately
105
+ # to the caller; override this method on your activerecord object to
106
+ # handle the errors in a custom fashion. Be sure to return true if you
107
+ # don't want the AR callbacks to halt execution.
108
+ #
109
+ def asari_on_error(exception)
110
+ raise exception
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,10 @@
1
+ class Asari
2
+ class MissingSearchDomainException < StandardError
3
+ end
4
+
5
+ class SearchException < StandardError
6
+ end
7
+
8
+ class DocumentUpdateException < StandardError
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ class Asari
2
+ VERSION = "0.3.0"
3
+ end
@@ -0,0 +1,105 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe Asari do
4
+ describe Asari::ActiveRecord do
5
+ describe "when CloudSearch is responding without error" do
6
+ before :each do
7
+ @asari = double()
8
+ ActiveRecordFake.instance_variable_set(:@asari, @asari)
9
+ end
10
+
11
+ it "correctly sets up a before_delete listener" do
12
+ expect(ActiveRecordFake.instance_variable_get(:@before_delete)).to eq(:asari_remove_from_index)
13
+ end
14
+
15
+ it "correctly sets up an after_create listener" do
16
+ expect(ActiveRecordFake.instance_variable_get(:@after_create)).to eq(:asari_add_to_index)
17
+ end
18
+
19
+ it "correctly sets up an after_update listener" do
20
+ expect(ActiveRecordFake.instance_variable_get(:@after_update)).to eq(:asari_update_in_index)
21
+ end
22
+
23
+ it "will automatically attempt to remove itself from the index" do
24
+ @asari.should_receive(:remove_item).with(1)
25
+ ActiveRecordFake.new.asari_remove_from_index
26
+ end
27
+
28
+ it "will automatically add itself to the index" do
29
+ @asari.should_receive(:add_item).with(1, {:name => "Fritters", :email => "fritters@aredelicious.com"})
30
+ ActiveRecordFake.new.asari_add_to_index
31
+ end
32
+
33
+ it "will automatically update itself in the index" do
34
+ @asari.should_receive(:update_item).with(1, {:name => "Fritters", :email => "fritters@aredelicious.com"})
35
+ ActiveRecordFake.new.asari_update_in_index
36
+ end
37
+
38
+ it "will allow you to search for items with the index" do
39
+ @asari.should_receive(:search).with("fritters").and_return(["1"])
40
+
41
+ ActiveRecordFake.asari_find("fritters")
42
+ end
43
+
44
+ it "will return a list of model objects when you search" do
45
+ @asari.should_receive(:search).with("fritters").and_return(["1"])
46
+
47
+ results = ActiveRecordFake.asari_find("fritters")
48
+ expect(results.class).to eq(Array)
49
+ expect(results[0].class).to eq(ActiveRecordFake)
50
+ end
51
+
52
+ it "will return an empty list when you search for a term that isn't in the index" do
53
+ @asari.should_receive(:search).with("veggie burgers").and_return([])
54
+
55
+ results = ActiveRecordFake.asari_find("veggie burgers")
56
+ expect(results.class).to eq(Array)
57
+ expect(results.size).to eq(0)
58
+ end
59
+ end
60
+
61
+ describe "When CloudSearch is being a problem" do
62
+ before :each do
63
+ ActiveRecordFake.instance_variable_set(:@asari, Asari.new("test-domain"))
64
+ stub_const("HTTParty", double())
65
+ HTTParty.stub(:post).and_return(fake_error_response)
66
+ HTTParty.stub(:get).and_return(fake_error_response)
67
+ end
68
+
69
+ it "will raise the Asari exception by default when adding to the index." do
70
+ expect { ActiveRecordFake.new.asari_add_to_index }.to raise_error(Asari::DocumentUpdateException)
71
+ end
72
+
73
+ it "will raise the Asari exception by default when updating the index." do
74
+ expect { ActiveRecordFake.new.asari_update_in_index }.to raise_error(Asari::DocumentUpdateException)
75
+ end
76
+
77
+ it "will raise the Asari exception by default when removing from index." do
78
+ expect { ActiveRecordFake.new.asari_remove_from_index }.to raise_error(Asari::DocumentUpdateException)
79
+ end
80
+
81
+ it "will always raise the Asari exception when searching in the index." do
82
+ expect { ActiveRecordFake.asari_find("fritters") }.to raise_error(Asari::SearchException)
83
+ end
84
+
85
+ describe "when we've overridden asari_on_error" do
86
+ it "honors asari_on_error when adding to the index." do
87
+ expect(ActiveRecordFakeWithErrorOverride.new.asari_add_to_index).to eq(false)
88
+ end
89
+
90
+ it "honors asari_on_error when updating in the index." do
91
+ expect(ActiveRecordFakeWithErrorOverride.new.asari_update_in_index).to eq(false)
92
+ end
93
+
94
+ it "honors asari_on_error when removing from the index." do
95
+ expect(ActiveRecordFakeWithErrorOverride.new.asari_remove_from_index).to eq(false)
96
+ end
97
+
98
+ it "still raises the Asari exception when searching." do
99
+ expect { ActiveRecordFakeWithErrorOverride.asari_find("fritters") }.to raise_error(Asari::SearchException)
100
+ end
101
+ end
102
+
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,28 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe "Asari" do
4
+ before :each do
5
+ @asari = Asari.new
6
+ end
7
+
8
+ describe "configuration" do
9
+ it "defaults to the first CloudSearch API version." do
10
+ expect(@asari.api_version).to eq "2011-02-01"
11
+ end
12
+
13
+ it "allows you to set a specific API version." do
14
+ @asari.api_version = "2015-10-21" # WE'VE GOT TO GO BACK
15
+ expect(@asari.api_version).to eq "2015-10-21"
16
+ end
17
+
18
+ it "raises an exeception if no search domain is provided." do
19
+ expect { @asari.search_domain }.to raise_error Asari::MissingSearchDomainException
20
+ end
21
+
22
+ it "allows you to set a search domain." do
23
+ @asari.search_domain = "theroyaldomainofawesome"
24
+ expect(@asari.search_domain).to eq "theroyaldomainofawesome"
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,66 @@
1
+ require_relative "../spec_helper"
2
+
3
+ describe Asari do
4
+ describe "updating the index" do
5
+ before :each do
6
+ @asari = Asari.new("testdomain")
7
+ stub_const("HTTParty", double())
8
+ HTTParty.stub(:post).and_return(fake_post_success)
9
+ end
10
+
11
+ it "allows you to add an item to the index." do
12
+ HTTParty.should_receive(:post).with("http://doc-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/documents/batch", { :body => [{ "type" => "add", "id" => "1", "version" => 1, "lang" => "en", "fields" => { :name => "fritters"}}].to_json, :headers => { "Content-Type" => "application/json"}})
13
+
14
+ expect(@asari.add_item("1", {:name => "fritters"})).to eq(nil)
15
+ end
16
+
17
+ it "allows you to update an item to the index." do
18
+ HTTParty.should_receive(:post).with("http://doc-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/documents/batch", { :body => [{ "type" => "add", "id" => "1", "version" => 1, "lang" => "en", "fields" => { :name => "fritters"}}].to_json, :headers => { "Content-Type" => "application/json"}})
19
+
20
+ expect(@asari.update_item("1", {:name => "fritters"})).to eq(nil)
21
+ end
22
+
23
+ it "allows you to delete an item from the index." do
24
+ HTTParty.should_receive(:post).with("http://doc-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/documents/batch", { :body => [{ "type" => "delete", "id" => "1", "version" => 2}].to_json, :headers => { "Content-Type" => "application/json"}})
25
+
26
+ expect(@asari.remove_item("1")).to eq(nil)
27
+ end
28
+
29
+ describe "when there are internet issues" do
30
+ before :each do
31
+ HTTParty.stub(:post).and_raise(SocketError.new)
32
+ end
33
+
34
+ it "raises an exception when you try to add an item to the index" do
35
+ expect { @asari.add_item("1", {})}.to raise_error(Asari::DocumentUpdateException)
36
+ end
37
+
38
+ it "raises an exception when you try to update an item in the index" do
39
+ expect { @asari.update_item("1", {})}.to raise_error(Asari::DocumentUpdateException)
40
+ end
41
+
42
+ it "raises an exception when you try to remove an item from the index" do
43
+ expect { @asari.remove_item("1")}.to raise_error(Asari::DocumentUpdateException)
44
+ end
45
+ end
46
+
47
+ describe "when there are CloudSearch issues" do
48
+ before :each do
49
+ HTTParty.stub(:post).and_return(fake_error_response)
50
+ end
51
+
52
+ it "raises an exception when you try to add an item to the index" do
53
+ expect { @asari.add_item("1", {})}.to raise_error(Asari::DocumentUpdateException)
54
+ end
55
+
56
+ it "raises an exception when you try to update an item in the index" do
57
+ expect { @asari.update_item("1", {})}.to raise_error(Asari::DocumentUpdateException)
58
+ end
59
+
60
+ it "raises an exception when you try to remove an item from the index" do
61
+ expect { @asari.remove_item("1")}.to raise_error(Asari::DocumentUpdateException)
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,40 @@
1
+ require_relative "../spec_helper"
2
+
3
+ describe Asari do
4
+ describe "searching" do
5
+ before :each do
6
+ @asari = Asari.new("testdomain")
7
+ stub_const("HTTParty", double())
8
+ HTTParty.stub(:get).and_return(fake_response)
9
+ end
10
+
11
+ it "allows you to search." do
12
+ HTTParty.should_receive(:get).with("http://search-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/search?q=testsearch")
13
+ @asari.search("testsearch")
14
+ end
15
+
16
+ it "escapes dangerous characters in search terms." do
17
+ HTTParty.should_receive(:get).with("http://search-testdomain.us-east-1.cloudsearch.amazonaws.com/2011-02-01/search?q=testsearch%21")
18
+ @asari.search("testsearch!")
19
+ end
20
+
21
+ it "returns a list of document IDs for search results." do
22
+ expect(@asari.search("testsearch")).to eq(["123","456"])
23
+ end
24
+
25
+ it "returns an empty list when no search results are found." do
26
+ HTTParty.stub(:get).and_return(fake_empty_response)
27
+ expect(@asari.search("testsearch")).to eq([])
28
+ end
29
+
30
+ it "raises an exception if the service errors out." do
31
+ HTTParty.stub(:get).and_return(fake_error_response)
32
+ expect { @asari.search("testsearch)") }.to raise_error Asari::SearchException
33
+ end
34
+
35
+ it "raises an exception if there are internet issues." do
36
+ HTTParty.stub(:get).and_raise(SocketError.new)
37
+ expect { @asari.search("testsearch)") }.to raise_error Asari::SearchException
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,78 @@
1
+ require 'asari'
2
+ require 'asari/active_record'
3
+ require 'ostruct'
4
+
5
+ RSpec.configuration.expect_with(:rspec) { |c| c.syntax = :expect }
6
+
7
+ def fake_response
8
+ OpenStruct.new(:parsed_response => { "hits" => {"hit" => [{"id" => "123"}, {"id" => "456"}]}},
9
+ :response => OpenStruct.new(:code => "200"))
10
+ end
11
+
12
+ def fake_empty_response
13
+ OpenStruct.new(:parsed_response => { "hits" => {"hit" => []}},
14
+ :response => OpenStruct.new(:code => "200"))
15
+ end
16
+
17
+ def fake_error_response
18
+ OpenStruct.new(:response => OpenStruct.new(:code => "404"))
19
+ end
20
+
21
+ def fake_post_success
22
+ OpenStruct.new(:response => OpenStruct.new(:code => "200"))
23
+ end
24
+
25
+ module ActiveRecord
26
+ class RecordNotFound < StandardError
27
+ end
28
+ end
29
+
30
+ class ActiveRecordFake
31
+ class << self
32
+ def before_delete(sym)
33
+ @before_delete = sym
34
+ end
35
+
36
+ def after_create(sym)
37
+ @after_create = sym
38
+ end
39
+
40
+ def after_update(sym)
41
+ @after_update = sym
42
+ end
43
+
44
+ def find(*args)
45
+ if args.size > 0
46
+ return [ActiveRecordFake.new]
47
+ else
48
+ raise ActiveRecord::RecordNotFound
49
+ end
50
+ end
51
+ end
52
+
53
+ include Asari::ActiveRecord
54
+
55
+ asari_index("test-domain", [:name, :email])
56
+
57
+ def id
58
+ 1
59
+ end
60
+
61
+ def name
62
+ "Fritters"
63
+ end
64
+
65
+ def email
66
+ "fritters@aredelicious.com"
67
+ end
68
+ end
69
+
70
+ class ActiveRecordFakeWithErrorOverride < ActiveRecordFake
71
+ include Asari::ActiveRecord
72
+
73
+ asari_index("test-domain", [:name, :email])
74
+
75
+ def self.asari_on_error(exception)
76
+ false
77
+ end
78
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: asari
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tommy Morgan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: httparty
16
+ requirement: &70106563512800 !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: *70106563512800
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &70106563528480 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70106563528480
36
+ description: Asari s a Ruby interface for AWS CloudSearch
37
+ email:
38
+ - tommy@wellbredgrapefruit.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - .gitignore
44
+ - Gemfile
45
+ - README.md
46
+ - Rakefile
47
+ - asari.gemspec
48
+ - lib/asari.rb
49
+ - lib/asari/active_record.rb
50
+ - lib/asari/exceptions.rb
51
+ - lib/asari/version.rb
52
+ - spec/active_record_spec.rb
53
+ - spec/asari_spec.rb
54
+ - spec/documents_spec.rb
55
+ - spec/search_spec.rb
56
+ - spec_helper.rb
57
+ homepage: http://github.com/duwanis/asari
58
+ licenses: []
59
+ post_install_message:
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubyforge_project: asari
77
+ rubygems_version: 1.8.15
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: Asari is a Ruby interface for AWS CloudSearch.
81
+ test_files:
82
+ - spec/active_record_spec.rb
83
+ - spec/asari_spec.rb
84
+ - spec/documents_spec.rb
85
+ - spec/search_spec.rb
86
+ has_rdoc: