em-stretcher 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +151 -0
- data/Rakefile +4 -0
- data/em-stretcher.gemspec +29 -0
- data/lib/em-stretcher.rb +19 -0
- data/lib/em/stretcher/index_type.rb +22 -0
- data/lib/em/stretcher/search_results.rb +32 -0
- data/lib/em/stretcher/server.rb +85 -0
- data/lib/em/stretcher/version.rb +5 -0
- data/spec/server_spec.rb +111 -0
- data/spec/spec_helper.rb +97 -0
- metadata +174 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: baa41f4d1deadbbb5bac9415dc9f6800fa89cff7
|
4
|
+
data.tar.gz: 79dd2a858e7cbcc507d45f50b20632656ed0635f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e6e01ba6d3c896b6ccaadf3c519983bac59946c8ee3e3b572ec0557b9c6f9d40d9d5475737e6dd59f14aa6bca8720883f4476604b6967cd961602a957877e94b
|
7
|
+
data.tar.gz: 4b626de495880b06323803c8e6404e1244765415b0268d18459a3c6d0f301ed2ca1d58d7d765975ce0e5a1c137e1a5a6b435fff15a442a501ed292835f49a9dc
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.0.0-p353
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Benjamin Coe
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
Em::Stretcher
|
2
|
+
=============
|
3
|
+
|
4
|
+
An EventMachine port of [Stretcher](https://github.com/PoseBiz/stretcher) (a Fast, Elegant, ElasticSearch client.)
|
5
|
+
|
6
|
+
Indexes
|
7
|
+
-------
|
8
|
+
|
9
|
+
**Creating an Index**
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
require 'eventmachine'
|
13
|
+
require "em-stretcher"
|
14
|
+
|
15
|
+
EM.run do
|
16
|
+
server = EM::Stretcher::Server.new
|
17
|
+
|
18
|
+
server.index('my-index').create
|
19
|
+
.callback do |result|
|
20
|
+
p result
|
21
|
+
end
|
22
|
+
.errback do |err|
|
23
|
+
p err
|
24
|
+
end
|
25
|
+
end
|
26
|
+
```
|
27
|
+
|
28
|
+
**Deleting an Index**
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
server.index('my-index').delete
|
32
|
+
.callback do |result|
|
33
|
+
p result
|
34
|
+
end
|
35
|
+
.errback do |err|
|
36
|
+
p err
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
Mappings
|
41
|
+
--------
|
42
|
+
|
43
|
+
**Creating a Mapping**
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
mapping = {
|
47
|
+
:article => {
|
48
|
+
properties: {
|
49
|
+
title: { :type => :string }
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
server.index('my-index')
|
55
|
+
.type('article')
|
56
|
+
.put_mapping(mapping)
|
57
|
+
.callback do |result|
|
58
|
+
p result
|
59
|
+
end
|
60
|
+
.errback do |err|
|
61
|
+
p err
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
Indexing Documents
|
66
|
+
------------------
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
id = 33
|
70
|
+
|
71
|
+
server.index('my-index')
|
72
|
+
.type(mapping_name)
|
73
|
+
.put(id, { title: "My Document with the id #{id}" })
|
74
|
+
.callback do |response|
|
75
|
+
p response
|
76
|
+
end
|
77
|
+
.errback do |err|
|
78
|
+
p err
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
Searching for Documents
|
83
|
+
-----------------------
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
server.index('my-index').type('articles')
|
87
|
+
.search(size: 50, query: { "query_string" => { "query" => "*" } })
|
88
|
+
.documents
|
89
|
+
.callback do |r|
|
90
|
+
p r
|
91
|
+
end
|
92
|
+
```
|
93
|
+
|
94
|
+
When One Thing Leads to Another
|
95
|
+
-------------------------------
|
96
|
+
|
97
|
+
EM::Stretcher uses [Deferrable Gratification](https://github.com/samstokes/deferrable_gratification) for chaining together dependent requests.
|
98
|
+
|
99
|
+
Here's a great example of when this comes into play:
|
100
|
+
|
101
|
+
* You index several hundred documents in parallel.
|
102
|
+
* You want to perform a search on the index, with all the documents present.
|
103
|
+
|
104
|
+
Here's how you can pull this off with Deferrable Gratification:
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
# Index some documents in parallel.
|
108
|
+
(0..50).each do |i|
|
109
|
+
server.index('my-index')
|
110
|
+
.type('articles')
|
111
|
+
.put(i, { title: "title #{i}" })
|
112
|
+
.callback do |response|
|
113
|
+
p response
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# First we wait for the indexing to finish.
|
118
|
+
server.index('my-index').refresh
|
119
|
+
.bind! do
|
120
|
+
|
121
|
+
# Then we perform the search.
|
122
|
+
server.index('my-index').type('articles')
|
123
|
+
.search(size: 50, query: { "query_string" => { "query" => "*" } })
|
124
|
+
.documents
|
125
|
+
.callback do |r|
|
126
|
+
p r # all 50 results should have been returned.
|
127
|
+
end
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
131
|
+
## Installation
|
132
|
+
|
133
|
+
Add this line to your application's Gemfile:
|
134
|
+
|
135
|
+
gem 'em-stretcher'
|
136
|
+
|
137
|
+
And then execute:
|
138
|
+
|
139
|
+
$ bundle
|
140
|
+
|
141
|
+
Or install it yourself as:
|
142
|
+
|
143
|
+
$ gem install em-stretcher
|
144
|
+
|
145
|
+
## Contributing
|
146
|
+
|
147
|
+
1. Fork it ( http://github.com/bcoe/em-stretcher/fork )
|
148
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
149
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
150
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
151
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'em/stretcher/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "em-stretcher"
|
8
|
+
spec.version = EventMachine::Stretcher::VERSION
|
9
|
+
spec.authors = ["Benjamin Coe"]
|
10
|
+
spec.email = ["ben@yesware.com"]
|
11
|
+
spec.summary = %q{EventMachine for Stretcher a Fast, Elegant, ElasticSearch client}
|
12
|
+
spec.homepage = ""
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency "stretcher"
|
21
|
+
spec.add_dependency "deferrable_gratification"
|
22
|
+
spec.add_dependency "eventmachine"
|
23
|
+
spec.add_dependency "em-http-request"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
26
|
+
spec.add_development_dependency "rspec"
|
27
|
+
spec.add_development_dependency "rspec-eventmachine"
|
28
|
+
spec.add_development_dependency "rake"
|
29
|
+
end
|
data/lib/em-stretcher.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require "ostruct"
|
2
|
+
require "stretcher"
|
3
|
+
require "eventmachine"
|
4
|
+
require "deferrable_gratification"
|
5
|
+
require "em-http-request"
|
6
|
+
require "em/stretcher/server"
|
7
|
+
require "em/stretcher/version"
|
8
|
+
require "em/stretcher/search_results"
|
9
|
+
require "em/stretcher/index_type"
|
10
|
+
|
11
|
+
module EventMachine
|
12
|
+
module Stretcher
|
13
|
+
# Your code goes here...
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Enchance deferrables with bind functionality.
|
18
|
+
DG.enhance_all_deferrables!
|
19
|
+
DG.enhance! EventMachine::HttpClient
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Patch get to play nicely with EM.
|
2
|
+
module Stretcher
|
3
|
+
# Represents an index scoped to a specific type.
|
4
|
+
# Generally should be instantiated via Index#type(name).
|
5
|
+
class IndexType
|
6
|
+
# Retrieves the document by ID.
|
7
|
+
# Normally this returns the contents of _source, however, if the 'raw' flag is passed in, it will return the full response hash.
|
8
|
+
# Returns nil if the document does not exist.
|
9
|
+
#
|
10
|
+
# The :fields argument can either be a csv String or an Array. e.g. [:field1,'field2] or "field1,field2".
|
11
|
+
# If the fields parameter is passed in those fields are returned instead of _source.
|
12
|
+
#
|
13
|
+
# If, you include _source as a field, along with other fields you MUST set the raw flag to true to
|
14
|
+
# receive both fields and _source. Otherwise, only _source will be returned
|
15
|
+
def get(id, options={})
|
16
|
+
request(:get, id, options)
|
17
|
+
.bind! do |res|
|
18
|
+
res._source || res.fields
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Patch search results to play nice with deferrables.
|
2
|
+
module Stretcher
|
3
|
+
# Conveniently represents elastic search results in a more compact fashion
|
4
|
+
#
|
5
|
+
# Available properties:
|
6
|
+
#
|
7
|
+
# * raw : The raw response from elastic search
|
8
|
+
# * total : The total number of matched docs
|
9
|
+
# * facets : the facets hash
|
10
|
+
# * results : The hit results with _id merged in to _source
|
11
|
+
class SearchResults
|
12
|
+
# Returns a 'prettier' version of elasticsearch results
|
13
|
+
# Also aliased as +docs+
|
14
|
+
# This will:
|
15
|
+
#
|
16
|
+
# 1. Return either '_source' or 'fields' as the base of the result
|
17
|
+
# 2. Merge any keys beginning with a '_' into it as well (such as '_score')
|
18
|
+
# 3. Copy the 'highlight' field into '_highlight'
|
19
|
+
#
|
20
|
+
def documents
|
21
|
+
raw_plain.bind! do |result|
|
22
|
+
result.hits.hits.map do |hit|
|
23
|
+
doc = extract_source(hit)
|
24
|
+
copy_underscores(hit, doc)
|
25
|
+
copy_highlight(hit, doc)
|
26
|
+
doc
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
alias_method :docs, :documents
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# Patch the stretcher server to use
|
2
|
+
# deferrables rather than Faraday.
|
3
|
+
module EventMachine::Stretcher
|
4
|
+
class Server < Stretcher::Server
|
5
|
+
# Handy way to query the server, returning *only* the body
|
6
|
+
# Will fail with an exception when the status is not in the 2xx range.
|
7
|
+
#
|
8
|
+
# @param method [Symbol] HTTP method to execute.
|
9
|
+
# @param path [String] full ES API URL to hit (http://127.0.0.1:9200/_status).
|
10
|
+
# @param body [Hash] Hash ElasticSearch query body.
|
11
|
+
# @param headers [Hash] additional headers.
|
12
|
+
# @param options [Options]
|
13
|
+
# @param options.mashify [Boolean] should the response be turned into a Hashie::Mash?
|
14
|
+
# @return [Deferrable] deferrable that yields ElasticSearch response.
|
15
|
+
def request(method, path, params={}, body=nil, headers={}, options={})
|
16
|
+
options = { :mashify => true }.merge(options)
|
17
|
+
|
18
|
+
# Rather than setting up the default headers using the
|
19
|
+
# Faraday middlewear, we set them here.
|
20
|
+
http_params = {
|
21
|
+
headers: headers.merge({
|
22
|
+
:accept => 'application/json',
|
23
|
+
:user_agent => "Stretcher Ruby Gem #{Stretcher::VERSION}",
|
24
|
+
"Content-Type" => "application/json"
|
25
|
+
})
|
26
|
+
}
|
27
|
+
|
28
|
+
deferrable = EventMachine::DefaultDeferrable.new
|
29
|
+
|
30
|
+
# Allow the body to be set via a block
|
31
|
+
# es_component.rb in the stretcher library.
|
32
|
+
body_struct = OpenStruct.new
|
33
|
+
yield(body_struct) if block_given?
|
34
|
+
body ||= body_struct.body
|
35
|
+
|
36
|
+
# Update params with GET and POST parameters.
|
37
|
+
http_params[:query] = Stretcher::Util.clean_params(params) if params
|
38
|
+
http_params[:body] = JSON.dump(body) if body
|
39
|
+
|
40
|
+
# Execute :get, :post, :put, or :delete, returns a deferrable.
|
41
|
+
http = EventMachine::HttpRequest.new(path).send(method, http_params)
|
42
|
+
|
43
|
+
# We return our own deferrable, so that we can parse results.
|
44
|
+
http.callback do
|
45
|
+
check_response(http, deferrable, options)
|
46
|
+
end
|
47
|
+
|
48
|
+
http.errback do |err|
|
49
|
+
deferrable.fail(err)
|
50
|
+
end
|
51
|
+
|
52
|
+
deferrable
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# Internal use only
|
58
|
+
# Check response codes from request
|
59
|
+
def check_response(res, deferrable, options)
|
60
|
+
status = res.response_header.status
|
61
|
+
|
62
|
+
if status >= 200 && status <= 299
|
63
|
+
if(options[:mashify])
|
64
|
+
begin
|
65
|
+
parsed_response = JSON.parse(res.response)
|
66
|
+
deferrable.succeed(Hashie::Mash.new(parsed_response))
|
67
|
+
rescue
|
68
|
+
deferrable.succeed(res.response)
|
69
|
+
end
|
70
|
+
else
|
71
|
+
deferrable.succeed(res.response)
|
72
|
+
end
|
73
|
+
elsif [404, 410].include? status
|
74
|
+
err_str = "Error processing request: (#{status})! #{res.req.method} URL: #{res.req.uri}"
|
75
|
+
err_str << "\n Resp Body: #{res.response}"
|
76
|
+
deferrable.fail(Stretcher::RequestError::NotFound.new(err_str))
|
77
|
+
else
|
78
|
+
err_str = "Error processing request (#{status})! #{res.req.method} URL: #{res.req.uri}"
|
79
|
+
err_str << "\n Resp Body: #{res.response}"
|
80
|
+
deferrable.fail(Stretcher::RequestError.new(err_str))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
data/spec/server_spec.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe EventMachine::Stretcher::Server do
|
4
|
+
|
5
|
+
include DeferrableModule
|
6
|
+
|
7
|
+
before(:all) { reset_index }
|
8
|
+
before(:each) { execute(type, :put_mapping, mapping) }
|
9
|
+
|
10
|
+
let(:server) { EventMachine::Stretcher::Server.new }
|
11
|
+
let(:index) { server.index(TESTING_INDEX_NAME) }
|
12
|
+
let(:type) { index.type(mapping_name) }
|
13
|
+
let(:mapping_name) { :article }
|
14
|
+
let(:mapping) do
|
15
|
+
{
|
16
|
+
mapping_name => {
|
17
|
+
properties: {
|
18
|
+
title: { :type => :string }
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
end
|
23
|
+
let(:document) do
|
24
|
+
{title: 'hello world!' }
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "index" do
|
28
|
+
it "can delete an index" do
|
29
|
+
execute(index, :delete)
|
30
|
+
execute(index, :status)
|
31
|
+
error_response_should_contain 'IndexMissingException'
|
32
|
+
end
|
33
|
+
|
34
|
+
it "can create an index" do
|
35
|
+
execute(index, :delete)
|
36
|
+
execute(index, :create, {
|
37
|
+
:settings => {
|
38
|
+
:number_of_shards => 3,
|
39
|
+
:number_of_replicas => 0
|
40
|
+
}
|
41
|
+
})
|
42
|
+
execute(index, :status)
|
43
|
+
success_key_should_have_value([:_shards, :total], 3)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "creating mappings" do
|
48
|
+
it "can create a mapping" do
|
49
|
+
type = index.type(mapping_name)
|
50
|
+
execute(type, :put_mapping, mapping)
|
51
|
+
execute(index, :get_mapping)
|
52
|
+
|
53
|
+
success_key_should_have_value([
|
54
|
+
TESTING_INDEX_NAME.to_sym,
|
55
|
+
mapping_name
|
56
|
+
], { "properties" => { "title" => { "type"=>"string" } } })
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "documents" do
|
61
|
+
it "can index a document" do
|
62
|
+
execute(type, :put, 1, document)
|
63
|
+
execute(index, :refresh)
|
64
|
+
execute(type, :search)
|
65
|
+
success_result_count_should_equal(1)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "can fetch a document by its id" do
|
69
|
+
execute(type, :put, 1, document)
|
70
|
+
execute(index, :refresh)
|
71
|
+
execute(type, :get, 1)
|
72
|
+
|
73
|
+
success_key_should_have_value(:title, 'hello world!')
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should return a 404 if document is not found" do
|
77
|
+
execute(type, :get, 2)
|
78
|
+
|
79
|
+
error_response_should_contain '404'
|
80
|
+
end
|
81
|
+
|
82
|
+
it "can delete a document" do
|
83
|
+
execute(type, :put, 1, document)
|
84
|
+
execute(index, :refresh)
|
85
|
+
execute(type, :delete, 1, document)
|
86
|
+
execute(index, :refresh)
|
87
|
+
|
88
|
+
execute(type, :search)
|
89
|
+
success_result_count_should_equal(0)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "search" do
|
94
|
+
it "returns a document if query matches title" do
|
95
|
+
execute(type, :put, 1, document)
|
96
|
+
execute(index, :refresh)
|
97
|
+
execute(type, :search, query: { "query_string" => { "query" => "hello world" } })
|
98
|
+
|
99
|
+
success_result_count_should_equal(1)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "does not return a document if query does not match title" do
|
103
|
+
execute(type, :put, 1, document)
|
104
|
+
execute(index, :refresh)
|
105
|
+
execute(type, :search, query: { "query_string" => { "query" => "zebra" } })
|
106
|
+
|
107
|
+
success_result_count_should_equal(0)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require "rspec"
|
2
|
+
require "rspec/em"
|
3
|
+
|
4
|
+
require_relative '../lib/em-stretcher'
|
5
|
+
|
6
|
+
TESTING_INDEX_NAME = 'em::stretcher:testing'
|
7
|
+
|
8
|
+
# Helper to reset ElasticSearch index for tests.
|
9
|
+
def reset_index
|
10
|
+
server = Stretcher::Server.new
|
11
|
+
i = server.index(TESTING_INDEX_NAME)
|
12
|
+
begin
|
13
|
+
i.delete
|
14
|
+
rescue Stretcher::RequestError::NotFound
|
15
|
+
end
|
16
|
+
server.refresh
|
17
|
+
i.create({
|
18
|
+
:settings => {
|
19
|
+
:number_of_shards => 1,
|
20
|
+
:number_of_replicas => 0
|
21
|
+
}
|
22
|
+
})
|
23
|
+
# Why do both? Doesn't hurt, and it fixes some races
|
24
|
+
server.refresh
|
25
|
+
i.refresh
|
26
|
+
|
27
|
+
attempts_left = 40
|
28
|
+
|
29
|
+
# Sometimes the index isn't instantly available
|
30
|
+
loop do
|
31
|
+
idx_metadata = server.cluster.request(:get, :state)[:metadata][:indices][i.name]
|
32
|
+
i_state = idx_metadata[:state]
|
33
|
+
|
34
|
+
break if i_state == 'open'
|
35
|
+
|
36
|
+
if attempts_left < 1
|
37
|
+
raise "Bad index state! #{i_state}. Metadata: #{idx_metadata}"
|
38
|
+
end
|
39
|
+
|
40
|
+
sleep 0.1
|
41
|
+
attempts_left -= 1
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# async assertions for EventMachine specs.
|
46
|
+
DeferrableModule = RSpec::EM.async_steps do
|
47
|
+
def execute(object, method, *args, &callback)
|
48
|
+
deferrable = if args
|
49
|
+
object.send(method, *args)
|
50
|
+
else
|
51
|
+
object.send(method)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Search results have their deferrable
|
55
|
+
# on the documents key.
|
56
|
+
if deferrable.respond_to?(:documents)
|
57
|
+
deferrable = deferrable.results
|
58
|
+
end
|
59
|
+
|
60
|
+
deferrable.callback do |result|
|
61
|
+
@success = result
|
62
|
+
callback.call
|
63
|
+
end
|
64
|
+
|
65
|
+
deferrable.errback do |err|
|
66
|
+
@error = err
|
67
|
+
callback.call
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# recursively look for a matching key and value in hash.
|
72
|
+
def success_key_should_have_value(key, expected, &callback)
|
73
|
+
# walk the hash structure.
|
74
|
+
key = [*key]
|
75
|
+
while key.count > 0
|
76
|
+
@success = @success.send(key.shift)
|
77
|
+
end
|
78
|
+
|
79
|
+
@success.should == expected
|
80
|
+
@success = nil
|
81
|
+
callback.call
|
82
|
+
end
|
83
|
+
|
84
|
+
# confirm count of result set.
|
85
|
+
def success_result_count_should_equal(expected, &callback)
|
86
|
+
@success.count.should == expected
|
87
|
+
@success = nil
|
88
|
+
callback.call
|
89
|
+
end
|
90
|
+
|
91
|
+
# look for substring in error http_response.
|
92
|
+
def error_response_should_contain(expected, &callback)
|
93
|
+
@error.http_response.should =~ /#{expected}/
|
94
|
+
@error = nil
|
95
|
+
callback.call
|
96
|
+
end
|
97
|
+
end
|
metadata
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: em-stretcher
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Benjamin Coe
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: stretcher
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: deferrable_gratification
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: eventmachine
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: em-http-request
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.5'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.5'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec-eventmachine
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rake
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description:
|
126
|
+
email:
|
127
|
+
- ben@yesware.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- .gitignore
|
133
|
+
- .rspec
|
134
|
+
- .ruby-version
|
135
|
+
- Gemfile
|
136
|
+
- LICENSE.txt
|
137
|
+
- README.md
|
138
|
+
- Rakefile
|
139
|
+
- em-stretcher.gemspec
|
140
|
+
- lib/em-stretcher.rb
|
141
|
+
- lib/em/stretcher/index_type.rb
|
142
|
+
- lib/em/stretcher/search_results.rb
|
143
|
+
- lib/em/stretcher/server.rb
|
144
|
+
- lib/em/stretcher/version.rb
|
145
|
+
- spec/server_spec.rb
|
146
|
+
- spec/spec_helper.rb
|
147
|
+
homepage: ''
|
148
|
+
licenses:
|
149
|
+
- MIT
|
150
|
+
metadata: {}
|
151
|
+
post_install_message:
|
152
|
+
rdoc_options: []
|
153
|
+
require_paths:
|
154
|
+
- lib
|
155
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - '>='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - '>='
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '0'
|
165
|
+
requirements: []
|
166
|
+
rubyforge_project:
|
167
|
+
rubygems_version: 2.2.1
|
168
|
+
signing_key:
|
169
|
+
specification_version: 4
|
170
|
+
summary: EventMachine for Stretcher a Fast, Elegant, ElasticSearch client
|
171
|
+
test_files:
|
172
|
+
- spec/server_spec.rb
|
173
|
+
- spec/spec_helper.rb
|
174
|
+
has_rdoc:
|