asari 0.3.0

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.
@@ -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: