swiftype-rb 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +387 -0
- data/Rakefile +1 -0
- data/lib/swiftype/base_model.rb +93 -0
- data/lib/swiftype/client.rb +30 -0
- data/lib/swiftype/configuration.rb +42 -0
- data/lib/swiftype/connection.rb +47 -0
- data/lib/swiftype/document.rb +17 -0
- data/lib/swiftype/document_type.rb +72 -0
- data/lib/swiftype/easy.rb +84 -0
- data/lib/swiftype/engine.rb +33 -0
- data/lib/swiftype/exceptions.rb +7 -0
- data/lib/swiftype/request.rb +34 -0
- data/lib/swiftype/search.rb +37 -0
- data/lib/swiftype/version.rb +3 -0
- data/lib/swiftype.rb +36 -0
- data/swiftype-rb.gemspec +28 -0
- metadata +122 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,387 @@
|
|
1
|
+
Swiftype Ruby Client (beta)
|
2
|
+
===
|
3
|
+
|
4
|
+
The official [Swiftype](http://swiftype.com) Ruby client for communicating with the Swiftype API. Learn more about Swiftype by visiting [swiftype.com](http://swiftype.com) and creating an account.
|
5
|
+
|
6
|
+
|
7
|
+
Prerequisites
|
8
|
+
---
|
9
|
+
1. A Swiftype account. Sign up at [swiftype.com](http://swiftype.com).
|
10
|
+
2. A compatible Ruby environment.
|
11
|
+
|
12
|
+
|
13
|
+
Installation
|
14
|
+
---
|
15
|
+
|
16
|
+
For now, just clone this repository and then pull in the library:
|
17
|
+
|
18
|
+
#### Bundler
|
19
|
+
|
20
|
+
gem 'swiftype-rb', :git => "https://github.com/swiftype/swiftype-rb.git", :require => 'swiftype'
|
21
|
+
|
22
|
+
#### Non-Bundler
|
23
|
+
|
24
|
+
git clone https://github.com/swiftype/swiftype-rb.git
|
25
|
+
|
26
|
+
rake build && rake install
|
27
|
+
|
28
|
+
require 'swiftype'
|
29
|
+
|
30
|
+
|
31
|
+
Overview
|
32
|
+
---
|
33
|
+
|
34
|
+
The client has a few basic methods on `Swiftype` for dealing with `Engines`. Beyond that, you can perform standard (CRUD) operations on any of the resources.
|
35
|
+
|
36
|
+
### Resources
|
37
|
+
|
38
|
+
#### Engine
|
39
|
+
|
40
|
+
`Engines` are the top-level objects in Swiftype. They have a free-form `name` field that is translated into a `slug` identifier.
|
41
|
+
|
42
|
+
#### Document Type
|
43
|
+
|
44
|
+
`DocumentTypes` specify the structure of a set of documents in the `Engine` and are the entry point for searches. There are three types of fields on a `DocumentType`: `:string`, `:text`, `:enum`, `:integer`, `:float`, and `:date`.
|
45
|
+
|
46
|
+
`:string` is for short strings that can be matched in both prefix and full-text searches. _Example: Chapter titles in a book._
|
47
|
+
|
48
|
+
`:text` can be long strings. They are meant for full-text searches only and will not be used for prefix queries. _Example: Entire text of an essay._
|
49
|
+
|
50
|
+
`:enum` are string traits of a document. They are not analyzed in any way, and thus can be used to filter and sort queries. _Example: Hardcover or paperback._
|
51
|
+
|
52
|
+
`:date` are ISO 8601 compatible time strings. They can also be used to filter and sort queries.
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
#### Document
|
57
|
+
|
58
|
+
`Documents` represent all of the pieces of content in an `Engine`. They are children of a `DocumentType` and conform to its field specification (note: you do *not* need to specify the fields ahead of time, they will be inferred by the contents of a document). When you perform a search on a `DocumentType`, you will receive `Document` results. `external_id` is the only required field for a `Document`. It can be any value, such as a numeric ID.
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
Basic Usage
|
63
|
+
===
|
64
|
+
|
65
|
+
Configuration:
|
66
|
+
---
|
67
|
+
|
68
|
+
Before issuing commands to the API, configure the client with your authentication credentials:
|
69
|
+
|
70
|
+
Swiftype.configure do |config|
|
71
|
+
config.username = "{YOUR_SWIFTYPE_LOGIN}"
|
72
|
+
config.password = "{YOUR_SWIFTYPE_PASSWORD}"
|
73
|
+
end
|
74
|
+
|
75
|
+
Indexing:
|
76
|
+
---
|
77
|
+
|
78
|
+
#### Engines:
|
79
|
+
|
80
|
+
Search engines are the top-level container for the objects you wish to search, and most sites will have a single engine. The engines themselves contain one or more document types, each of which contain the documents themselves.
|
81
|
+
|
82
|
+
Create a search engine:
|
83
|
+
|
84
|
+
engine = Swiftype::Engine.new(:name => 'bookstore')
|
85
|
+
engine.create!
|
86
|
+
|
87
|
+
Get a search engine:
|
88
|
+
|
89
|
+
Swiftype::Engine.find('bookstore')
|
90
|
+
|
91
|
+
Delete a search engine:
|
92
|
+
|
93
|
+
engine = Swiftype::Engine.find('bookstore')
|
94
|
+
engine.destroy!
|
95
|
+
|
96
|
+
|
97
|
+
#### Document Types
|
98
|
+
|
99
|
+
Create a `document_type`:
|
100
|
+
|
101
|
+
engine = Swiftype::Engine.find('bookstore')
|
102
|
+
type = engine.create_document_type(:name => 'books')
|
103
|
+
|
104
|
+
Get a `document_type`:
|
105
|
+
|
106
|
+
engine = Swiftype::Engine.find('bookstore')
|
107
|
+
type = engine.document_type('books')
|
108
|
+
|
109
|
+
Delete a `document_type`. Deleting a `document_type` will also delete every `document` contained within it:
|
110
|
+
|
111
|
+
engine = Swiftype::Engine.find('bookstore')
|
112
|
+
engine.destroy_document_type('books')
|
113
|
+
|
114
|
+
or, alternatively, call destroy on the `document_type` itself:
|
115
|
+
|
116
|
+
engine = Swiftype::Engine.find('bookstore')
|
117
|
+
type = engine.document_type('books')
|
118
|
+
type.destroy!
|
119
|
+
|
120
|
+
|
121
|
+
#### Documents
|
122
|
+
|
123
|
+
Create a `document`:
|
124
|
+
|
125
|
+
engine = Swiftype::Engine.find('bookstore')
|
126
|
+
type = engine.document_type('books')
|
127
|
+
type.create_document({
|
128
|
+
:external_id => '1',
|
129
|
+
:fields => [
|
130
|
+
{:name => 'title', :value => 'Information Retrieval', :type => 'string'},
|
131
|
+
{:name => 'genre', :value => 'non-fiction', :type => 'enum'},
|
132
|
+
{:name => 'author', :value => 'Stefan Buttcher', :type => 'string'},
|
133
|
+
{:name => 'in_stock', :value => true, :type => 'enum'},
|
134
|
+
{:name => 'on_sale', :value => false, :type => 'enum'}
|
135
|
+
]});
|
136
|
+
|
137
|
+
Get a `document`:
|
138
|
+
|
139
|
+
engine = Swiftype::Engine.find('bookstore')
|
140
|
+
type = engine.document_type('books')
|
141
|
+
doc = type.document('1')
|
142
|
+
|
143
|
+
Get every `document` within a `document_type`:
|
144
|
+
|
145
|
+
engine = Swiftype::Engine.find('bookstore')
|
146
|
+
type = engine.document_type('books')
|
147
|
+
type.documents
|
148
|
+
|
149
|
+
Update field(s) of a `document`:
|
150
|
+
|
151
|
+
engine = Swiftype::Engine.find('bookstore')
|
152
|
+
type = engine.document_type('books')
|
153
|
+
doc = type.document('1')
|
154
|
+
doc.update_fields!({:in_stock => false })
|
155
|
+
|
156
|
+
or, alternatively, update a `document` without retrieving it first:
|
157
|
+
|
158
|
+
engine = Swiftype::Engine.find('bookstore')
|
159
|
+
type = engine.document_type('books')
|
160
|
+
type.update_document(:external_id => '1', :fields => { :in_stock => false })
|
161
|
+
|
162
|
+
you can also update multiple fields in the same call:
|
163
|
+
|
164
|
+
doc.update_fields({:in_stock => false, :on_sale => true })
|
165
|
+
|
166
|
+
Delete a `document`:
|
167
|
+
|
168
|
+
engine = Swiftype::Engine.find('bookstore')
|
169
|
+
type = engine.document_type('books')
|
170
|
+
doc = type.document('1')
|
171
|
+
doc.destroy!
|
172
|
+
|
173
|
+
or, alternatively, delete a `document` without retrieving it first:
|
174
|
+
|
175
|
+
engine = Swiftype::Engine.find('bookstore')
|
176
|
+
type = engine.document_type('books')
|
177
|
+
type.destroy_document('1')
|
178
|
+
|
179
|
+
|
180
|
+
#### Bulk Operations
|
181
|
+
|
182
|
+
Bulk operations will allow you to perform rapid indexing updates and avoid the latency overhead of making repeated requests.
|
183
|
+
|
184
|
+
Create `document`s in bulk:
|
185
|
+
|
186
|
+
engine = Swiftype::Engine.find('bookstore')
|
187
|
+
type = engine.document_type('books')
|
188
|
+
type.create_documents([{
|
189
|
+
:external_id => '2',
|
190
|
+
:fields => [
|
191
|
+
{:name => 'title', :value => 'Lucene in Action', :type => 'string'},
|
192
|
+
{:name => 'genre', :value => 'non-fiction', :type => 'enum'},
|
193
|
+
{:name => 'author', :value => 'Michael McCandless', :type => 'string'},
|
194
|
+
{:name => 'in_stock', :value => true, :type => 'enum'},
|
195
|
+
{:name => 'on_sale', :value => false, :type => 'enum'}
|
196
|
+
]},{
|
197
|
+
:external_id => '3',
|
198
|
+
:fields => [
|
199
|
+
{:name => 'title', :value => 'MongoDB in Action', :type => 'string'},
|
200
|
+
{:name => 'genre', :value => 'non-fiction', :type => 'enum'},
|
201
|
+
{:name => 'author', :value => 'Kyle Banker', :type => 'string'},
|
202
|
+
{:name => 'in_stock', :value => true, :type => 'enum'},
|
203
|
+
{:name => 'on_sale', :value => false, :type => 'enum'}
|
204
|
+
]},{
|
205
|
+
:external_id => '4',
|
206
|
+
:fields => [
|
207
|
+
{:name => 'title', :value => 'The Great Gatsby', :type => 'string'},
|
208
|
+
{:name => 'genre', :value => 'fiction', :type => 'enum'},
|
209
|
+
{:name => 'author', :value => 'F. Scott Fitzgerald', :type => 'string'},
|
210
|
+
{:name => 'in_stock', :value => true, :type => 'enum'},
|
211
|
+
{:name => 'on_sale', :value => false, :type => 'enum'}
|
212
|
+
]}
|
213
|
+
])
|
214
|
+
|
215
|
+
Update `document`s in bulk:
|
216
|
+
|
217
|
+
engine = Swiftype::Engine.find('bookstore')
|
218
|
+
type = engine.document_type('books')
|
219
|
+
type.update_documents([
|
220
|
+
{:external_id => '2', :fields => {:in_stock => false, :on_sale => 'false'}},
|
221
|
+
{:external_id => '3', :fields => {:in_stock => false, :on_sale => 'false'}}
|
222
|
+
])
|
223
|
+
|
224
|
+
Delete `document`s in bulk:
|
225
|
+
|
226
|
+
engine = Swiftype::Engine.find('bookstore')
|
227
|
+
type = engine.document_type('books')
|
228
|
+
type.destroy_documents(['1','2','3','4'])
|
229
|
+
|
230
|
+
|
231
|
+
Searching:
|
232
|
+
---
|
233
|
+
|
234
|
+
#### Full text search
|
235
|
+
|
236
|
+
Search a `document_type` for the query "lucene":
|
237
|
+
|
238
|
+
engine = Swiftype::Engine.find('bookstore')
|
239
|
+
type = engine.document_type('books')
|
240
|
+
results = type.search("lucene")
|
241
|
+
|
242
|
+
You can pass the following options to the search method: `page`, `per_page`, `fetch_fields`, `search_fields`, and `filters`.
|
243
|
+
|
244
|
+
* `page` should be an integer of the page of results you want
|
245
|
+
* `per_page` should be an integer of the number of results you want from each page
|
246
|
+
* `fetch_fields` is a hash containing arrays of the fields you want to have returned for each object of each document_type
|
247
|
+
* `search_fields` is a hash containing arrays of the fields you want to match your query against for each object of each document_type
|
248
|
+
* `functional_boosts` is a hash containing boosts that are to be applied to numerically valued fields
|
249
|
+
* `filters` is a hash specifying additional conditions that should be applied to your query for each document_type
|
250
|
+
|
251
|
+
An example of using search options is as follows:
|
252
|
+
|
253
|
+
results = type.search('lucene', :filters => { :books => { :in_stock => false, :genre => 'fiction' }}, :per_page => 10, :page => 2, :fetch_fields => {:books => ['title','genre']}, :search_fields => {:books => ['title']})
|
254
|
+
|
255
|
+
Filters also support datetime range queries. For example, to return only those books with an `updated_at` field between `2012-02-16` and now, use the following filter:
|
256
|
+
|
257
|
+
results = type.search('lucene', :filters => { :books => { :updated_at => '[2012-02-16 TO *]' }})
|
258
|
+
|
259
|
+
|
260
|
+
##### Functional Boosts
|
261
|
+
|
262
|
+
Functional boosts allow you to boost result scores based on some numerically valued field. For example, you might want your search engine to return the most popular books first, so you would boost results on the `total_purchases` field, which contains an `integer` of the total number of purchases of that book:
|
263
|
+
|
264
|
+
results = type.search('lucene', :functional_boosts => { :books => { :total_purchases => 'logarithmic' }})
|
265
|
+
|
266
|
+
There are 3 types of functional boosts:
|
267
|
+
|
268
|
+
* `logarithmic` - multiplies the original score by log(numeric_value)
|
269
|
+
* `exponential` - multiplies the original score by exp(numeric_value)
|
270
|
+
* `linear` - multiplies the original score numeric_value
|
271
|
+
|
272
|
+
Functional boosts may be applied to `integer` and `float` valued fields.
|
273
|
+
|
274
|
+
#### Autocomplete
|
275
|
+
|
276
|
+
Get autocomplete suggestions from a `document_type` for the prefix "act"
|
277
|
+
|
278
|
+
engine = Swiftype::Engine.find('bookstore')
|
279
|
+
type = engine.document_type('books')
|
280
|
+
results = type.suggest("act")
|
281
|
+
|
282
|
+
The suggest method also accepts the same options specified for the search method above.
|
283
|
+
|
284
|
+
|
285
|
+
Simple Client:
|
286
|
+
===
|
287
|
+
The Simple Client is a convenience class that gives you basic, direct access to the Swiftype REST API, without mapping each call to the intermediate objects seen in the examples above. These methods will be more performant, because they avoid unnecessary round-trips to the server, but you will also have to provide more information to each call. Choose whatever suites your use-case.
|
288
|
+
|
289
|
+
#### Create a Simple Client
|
290
|
+
|
291
|
+
client = Swiftype::Easy.new
|
292
|
+
|
293
|
+
#### Search
|
294
|
+
|
295
|
+
results = client.search('bookstore',{SEARCH QUERY} [, OPTIONAL SEARCH OPTIONS])
|
296
|
+
|
297
|
+
#### Autocomplete
|
298
|
+
|
299
|
+
results = client.suggest('bookstore',{AUTOCOMPLETE PREFIX QUERY} [, OPTIONAL SEARCH OPTIONS])
|
300
|
+
|
301
|
+
#### Engines
|
302
|
+
|
303
|
+
client.engines # retrieves every engine
|
304
|
+
client.create_engine(:name => 'bookstore')
|
305
|
+
client.destroy_engine('bookstore')
|
306
|
+
|
307
|
+
#### Document Types
|
308
|
+
|
309
|
+
client.document_types('bookstore')
|
310
|
+
client.create_document_type('bookstore', :name => 'books')
|
311
|
+
client.destroy_document_type('bookstore', 'books')
|
312
|
+
|
313
|
+
#### Documents
|
314
|
+
|
315
|
+
# retrieve all documents
|
316
|
+
client.documents('bookstore', 'books')
|
317
|
+
|
318
|
+
# create a document
|
319
|
+
client.create_document('bookstore', 'books', {
|
320
|
+
:external_id => '1',
|
321
|
+
:fields => [
|
322
|
+
{:name => 'title', :value => 'Information Retrieval', :type => 'string'},
|
323
|
+
{:name => 'genre', :value => 'non-fiction', :type => 'enum'},
|
324
|
+
{:name => 'author', :value => 'Stefan Buttcher', :type => 'string'},
|
325
|
+
{:name => 'in_stock', :value => true, :type => 'enum'},
|
326
|
+
{:name => 'on_sale', :value => false, :type => 'enum'}
|
327
|
+
]})
|
328
|
+
|
329
|
+
# create documents in bulk
|
330
|
+
client.create_documents('bookstore', 'books', [{
|
331
|
+
:external_id => '2',
|
332
|
+
:fields => [
|
333
|
+
{:name => 'title', :value => 'Lucene in Action', :type => 'string'},
|
334
|
+
{:name => 'genre', :value => 'non-fiction', :type => 'enum'},
|
335
|
+
{:name => 'author', :value => 'Michael McCandless', :type => 'string'},
|
336
|
+
{:name => 'in_stock', :value => true, :type => 'enum'},
|
337
|
+
{:name => 'on_sale', :value => false, :type => 'enum'}
|
338
|
+
]},{
|
339
|
+
:external_id => '3',
|
340
|
+
:fields => [
|
341
|
+
{:name => 'title', :value => 'MongoDB in Action', :type => 'string'},
|
342
|
+
{:name => 'genre', :value => 'non-fiction', :type => 'enum'},
|
343
|
+
{:name => 'author', :value => 'Kyle Banker', :type => 'string'},
|
344
|
+
{:name => 'in_stock', :value => true, :type => 'enum'},
|
345
|
+
{:name => 'on_sale', :value => false, :type => 'enum'}
|
346
|
+
]}])
|
347
|
+
|
348
|
+
# update a document
|
349
|
+
client.update_document('bookstore','books','1', { :in_stock => false })
|
350
|
+
|
351
|
+
# update documents in bulk
|
352
|
+
client.update_documents('bookstore','books', [
|
353
|
+
{:external_id => '2', :fields => {:in_stock => false}},
|
354
|
+
{:external_id => '3', :fields => {:in_stock => true}}
|
355
|
+
])
|
356
|
+
|
357
|
+
# create or update a document
|
358
|
+
client.create_or_update_document('bookstore', 'books', {
|
359
|
+
:external_id => '1',
|
360
|
+
:fields => [
|
361
|
+
{:name => 'title', :value => 'Information Retrieval', :type => 'string'},
|
362
|
+
{:name => 'genre', :value => 'non-fiction', :type => 'enum'},
|
363
|
+
{:name => 'author', :value => 'Stefan Buttcher', :type => 'string'},
|
364
|
+
{:name => 'in_stock', :value => false, :type => 'enum'},
|
365
|
+
{:name => 'on_sale', :value => true, :type => 'enum'}
|
366
|
+
]})
|
367
|
+
|
368
|
+
# destroy a document
|
369
|
+
client.destroy_document('bookstore','books','1')
|
370
|
+
|
371
|
+
# destroy documents in bulk
|
372
|
+
client.destroy_documents('bookstore','books',['1','2','3'])
|
373
|
+
|
374
|
+
|
375
|
+
Todo
|
376
|
+
===
|
377
|
+
|
378
|
+
+ Proper response code handling for non-successful requests.
|
379
|
+
+ Publish gem to rubygems.org
|
380
|
+
+ Tests!
|
381
|
+
|
382
|
+
|
383
|
+
Questions?
|
384
|
+
===
|
385
|
+
Get in touch! We would be happy to help you get up and running.
|
386
|
+
|
387
|
+
[Quin](mailto:quin@swiftype.com) and [Matt](mailto:matt@swiftype.com) from [Swiftype](http://swiftype.com)
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
|
3
|
+
module Swiftype
|
4
|
+
class BaseModel < OpenStruct
|
5
|
+
include Swiftype::Connection
|
6
|
+
include Swiftype::Request
|
7
|
+
|
8
|
+
class << self
|
9
|
+
attr_reader :parent_classes
|
10
|
+
|
11
|
+
def model_name
|
12
|
+
name.split('::').last.underscore
|
13
|
+
end
|
14
|
+
|
15
|
+
def collection_name
|
16
|
+
model_name.pluralize
|
17
|
+
end
|
18
|
+
|
19
|
+
def parents(*parent_classes)
|
20
|
+
@parent_classes = parent_classes
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def id
|
25
|
+
self._id
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_hash
|
29
|
+
table
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_json
|
33
|
+
to_hash.to_json
|
34
|
+
end
|
35
|
+
|
36
|
+
def create!
|
37
|
+
update_with! post(path_to_collection, {self.class.model_name => to_hash})
|
38
|
+
end
|
39
|
+
|
40
|
+
def update!
|
41
|
+
update_with! put(path_to_model, {self.class.model_name => to_hash})
|
42
|
+
end
|
43
|
+
|
44
|
+
def destroy!
|
45
|
+
!!delete(path_to_model)
|
46
|
+
end
|
47
|
+
|
48
|
+
def path_to_model
|
49
|
+
"#{raw_path_to_model}.json"
|
50
|
+
end
|
51
|
+
|
52
|
+
def raw_path_to_model
|
53
|
+
path = (self.class.parent_classes || []).inject("") do |_, parent|
|
54
|
+
parent_id = send("#{parent.model_name}_id")
|
55
|
+
_ += "#{parent.collection_name}/#{parent_id}/"
|
56
|
+
_
|
57
|
+
end
|
58
|
+
"#{path}#{self.class.collection_name}/#{identifier}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def path_to_collection
|
62
|
+
"#{raw_path_to_collection}.json"
|
63
|
+
end
|
64
|
+
|
65
|
+
def raw_path_to_collection
|
66
|
+
path = (self.class.parent_classes || []).inject("") do |_, parent|
|
67
|
+
parent_id = send("#{parent.model_name}_id")
|
68
|
+
_ += "#{parent.collection_name}/#{parent_id}/"
|
69
|
+
_
|
70
|
+
end
|
71
|
+
"#{path}#{self.class.collection_name}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def update_with!(hash)
|
75
|
+
hash.each do |k, v|
|
76
|
+
send "#{k}=", v
|
77
|
+
end
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
def reload
|
82
|
+
update_with! get(path_to_model)
|
83
|
+
end
|
84
|
+
|
85
|
+
def identifier
|
86
|
+
slugged? ? slug : id
|
87
|
+
end
|
88
|
+
|
89
|
+
def slugged?
|
90
|
+
respond_to?(:slug)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Swiftype
|
2
|
+
class Client
|
3
|
+
include Swiftype::Connection
|
4
|
+
|
5
|
+
def initialize(options={})
|
6
|
+
end
|
7
|
+
|
8
|
+
module Engine
|
9
|
+
def engine(id)
|
10
|
+
Swiftype::Engine.find(id)
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_engine(attributes)
|
14
|
+
Swiftype::Engine.new(attributes).create!
|
15
|
+
end
|
16
|
+
|
17
|
+
def update_engine(id, attributes)
|
18
|
+
engine = Swiftype::Engine.find(id)
|
19
|
+
engine.merge!(attributes)
|
20
|
+
engine.update!(attributes)
|
21
|
+
end
|
22
|
+
|
23
|
+
def destroy_engine(id)
|
24
|
+
Swiftype::Engine.find(id).destroy!
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
include Swiftype::Client::Engine
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'swiftype/version'
|
2
|
+
|
3
|
+
module Swiftype
|
4
|
+
module Configuration
|
5
|
+
DEFAULT_ENDPOINT = "http://api.swiftype.com/api/v1/"
|
6
|
+
DEFAULT_USER_AGENT = "Swiftype-Ruby/#{Swiftype::VERSION}"
|
7
|
+
|
8
|
+
VALID_OPTIONS_KEYS = [
|
9
|
+
:username,
|
10
|
+
:password,
|
11
|
+
:api_key,
|
12
|
+
:user_agent,
|
13
|
+
:endpoint
|
14
|
+
]
|
15
|
+
|
16
|
+
attr_accessor *VALID_OPTIONS_KEYS
|
17
|
+
|
18
|
+
def self.extended(base)
|
19
|
+
base.reset
|
20
|
+
end
|
21
|
+
|
22
|
+
def reset
|
23
|
+
self.username = nil
|
24
|
+
self.password = nil
|
25
|
+
self.api_key = nil
|
26
|
+
self.endpoint = DEFAULT_ENDPOINT
|
27
|
+
self.user_agent = DEFAULT_USER_AGENT
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def configure
|
32
|
+
yield self
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def options
|
37
|
+
options = {}
|
38
|
+
VALID_OPTIONS_KEYS.each{|k| options[k] = send(k)}
|
39
|
+
options
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Swiftype
|
2
|
+
module Connection
|
3
|
+
include Swiftype::Request
|
4
|
+
|
5
|
+
def connection
|
6
|
+
raise(InvalidCredentials, "You must supply credentials to Swiftype.configure") unless (Swiftype.username && Swiftype.password ) || Swiftype.api_key
|
7
|
+
|
8
|
+
@connection ||= begin
|
9
|
+
conn = Faraday.new(Swiftype.endpoint) do |b|
|
10
|
+
b.response :raise_error
|
11
|
+
b.use Faraday::Request::UrlEncoded
|
12
|
+
b.use FaradayMiddleware::ParseJson
|
13
|
+
b.use FaradayMiddleware::Mashify
|
14
|
+
b.use ApiResponseMiddleware
|
15
|
+
b.adapter Faraday.default_adapter
|
16
|
+
end
|
17
|
+
|
18
|
+
conn.basic_auth Swiftype.username, Swiftype.password if Swiftype.username && Swiftype.password
|
19
|
+
conn.headers['User-Agent'] = Swiftype.user_agent
|
20
|
+
|
21
|
+
conn
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class ApiResponseMiddleware < Faraday::Response::Middleware
|
26
|
+
def on_complete(env)
|
27
|
+
case env[:status]
|
28
|
+
when 200, 201, 204
|
29
|
+
nil
|
30
|
+
when 401
|
31
|
+
raise InvalidCredentials
|
32
|
+
when 404
|
33
|
+
raise NonExistentRecord
|
34
|
+
when 409
|
35
|
+
raise RecordAlreadyExists
|
36
|
+
else
|
37
|
+
raise UnexpectedHTTPException, env[:body]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize(app)
|
42
|
+
super
|
43
|
+
@parser = nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Swiftype
|
2
|
+
class Document < BaseModel
|
3
|
+
parents Engine, DocumentType
|
4
|
+
|
5
|
+
def engine
|
6
|
+
Engine.find engine_id
|
7
|
+
end
|
8
|
+
|
9
|
+
def document_type
|
10
|
+
DocumentType.find document_type_id
|
11
|
+
end
|
12
|
+
|
13
|
+
def update_fields!(hash)
|
14
|
+
update_with! put("#{raw_path_to_model}/update_fields.json", {:fields => hash})
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Swiftype
|
2
|
+
class DocumentType < BaseModel
|
3
|
+
parents Engine
|
4
|
+
include Swiftype::Search
|
5
|
+
|
6
|
+
def build_document(params={})
|
7
|
+
Document.new({
|
8
|
+
:document_type_id => id || slug,
|
9
|
+
:engine_id => engine_id
|
10
|
+
}.merge(params))
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_document(params={})
|
14
|
+
doc = build_document(params)
|
15
|
+
doc.create!
|
16
|
+
doc
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_documents(documents=[])
|
20
|
+
post("engines/#{engine_id}/document_types/#{slug}/documents/bulk_create.json", {:documents => documents})
|
21
|
+
end
|
22
|
+
|
23
|
+
def update_documents(documents=[])
|
24
|
+
put("engines/#{engine_id}/document_types/#{slug}/documents/bulk_update.json", {:documents => documents})
|
25
|
+
end
|
26
|
+
|
27
|
+
def update_document(document={})
|
28
|
+
document_id = document[:external_id]
|
29
|
+
put("engines/#{engine_id}/document_types/#{slug}/documents/#{document_id}/update_fields", {:fields => document[:fields]})
|
30
|
+
end
|
31
|
+
|
32
|
+
def destroy_document(document_id)
|
33
|
+
!!delete("engines/#{engine_id}/document_types/#{slug}/documents/#{document_id}")
|
34
|
+
rescue NonExistentRecord
|
35
|
+
false
|
36
|
+
end
|
37
|
+
|
38
|
+
def destroy_documents(document_ids=[])
|
39
|
+
post("engines/#{engine_id}/document_types/#{slug}/documents/bulk_destroy.json", {:documents => document_ids})
|
40
|
+
rescue NonExistentRecord
|
41
|
+
false
|
42
|
+
end
|
43
|
+
|
44
|
+
def document(id)
|
45
|
+
Document.new get("engines/#{engine_id}/document_types/#{slug}/documents/#{id}.json")
|
46
|
+
end
|
47
|
+
|
48
|
+
def engine
|
49
|
+
Engine.find(engine_id)
|
50
|
+
end
|
51
|
+
|
52
|
+
def documents
|
53
|
+
get("engines/#{engine_id}/document_types/#{slug}/documents.json").map { |d| Document.new(d) }
|
54
|
+
end
|
55
|
+
|
56
|
+
def suggest(query, options={})
|
57
|
+
search_params = { :q => query }.merge(parse_suggest_options(options))
|
58
|
+
response = get("engines/#{engine_id}/document_types/#{slug}/suggest.json", search_params)
|
59
|
+
results = {}
|
60
|
+
response['records'].each { |document_type, records| results[document_type] = records.map { |d| Swiftype::Document.new(d) }}
|
61
|
+
results
|
62
|
+
end
|
63
|
+
|
64
|
+
def search(query, options={})
|
65
|
+
search_params = { :q => query }.merge(parse_search_options(options))
|
66
|
+
response = get("engines/#{engine_id}/document_types/#{slug}/search.json", search_params)
|
67
|
+
results = {}
|
68
|
+
response['records'].each { |document_type, records| results[document_type] = records.map { |d| Swiftype::Document.new(d) }}
|
69
|
+
results
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'swiftype/document'
|
2
|
+
|
3
|
+
module Swiftype
|
4
|
+
class Easy
|
5
|
+
include Swiftype::Connection
|
6
|
+
include Swiftype::Search
|
7
|
+
|
8
|
+
def initialize(options={})
|
9
|
+
end
|
10
|
+
|
11
|
+
module Engine
|
12
|
+
def engines
|
13
|
+
test_search_module
|
14
|
+
get("engines.json")
|
15
|
+
end
|
16
|
+
def create_engine(engine={})
|
17
|
+
post("engines.json", :engine => engine)
|
18
|
+
end
|
19
|
+
def destroy_engine(engine_id)
|
20
|
+
delete("engines/#{engine_id}")
|
21
|
+
end
|
22
|
+
def suggest(engine_id, query, options={})
|
23
|
+
search_params = { :q => query }.merge(parse_suggest_options(options))
|
24
|
+
response = get("engines/#{engine_id}/suggest.json", search_params)
|
25
|
+
results = {}
|
26
|
+
response['records'].each { |document_type, records| results[document_type] = records.map { |d| Swiftype::Document.new(d) }}
|
27
|
+
results
|
28
|
+
end
|
29
|
+
def search(engine_id, query, options={})
|
30
|
+
search_params = { :q => query }.merge(parse_search_options(options))
|
31
|
+
response = get("engines/#{engine_id}/search.json", search_params)
|
32
|
+
results = {}
|
33
|
+
response['records'].each { |document_type, records| results[document_type] = records.map { |d| Swiftype::Document.new(d) }}
|
34
|
+
results
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module DocumentType
|
39
|
+
def document_types(engine_id)
|
40
|
+
get("engines/#{engine_id}/document_types.json")
|
41
|
+
end
|
42
|
+
def create_document_type(engine_id, document_type={})
|
43
|
+
post("engines/#{engine_id}/document_types.json", :document_type => document_type)
|
44
|
+
end
|
45
|
+
def destroy_document_type(engine_id, document_type_id)
|
46
|
+
delete("engines/#{engine_id}/document_types/#{document_type_id}")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
module Document
|
51
|
+
def documents(engine_id, document_type_id)
|
52
|
+
get("engines/#{engine_id}/document_types/#{document_type_id}/documents.json")
|
53
|
+
end
|
54
|
+
def create_document(engine_id, document_type_id, document={})
|
55
|
+
post("engines/#{engine_id}/document_types/#{document_type_id}/documents.json", :document => document)
|
56
|
+
end
|
57
|
+
def create_documents(engine_id, document_type_id, documents=[])
|
58
|
+
post("engines/#{engine_id}/document_types/#{document_type_id}/documents/bulk_create.json", :documents => documents)
|
59
|
+
end
|
60
|
+
def destroy_document(engine_id, document_type_id, document_id)
|
61
|
+
delete("engines/#{engine_id}/document_types/#{document_type_id}/documents/#{document_id}")
|
62
|
+
end
|
63
|
+
def destroy_documents(engine_id, document_type_id, document_ids=[])
|
64
|
+
post("engines/#{engine_id}/document_types/#{document_type_id}/documents/bulk_destroy.json", :documents => document_ids)
|
65
|
+
end
|
66
|
+
def create_or_update_document(engine_id, document_type_id, document={})
|
67
|
+
post("engines/#{engine_id}/document_types/#{document_type_id}/documents/create_or_update.json", :document => document)
|
68
|
+
end
|
69
|
+
def create_or_update_documents(engine_id, document_type_id, documents=[])
|
70
|
+
post("engines/#{engine_id}/document_types/#{document_type_id}/documents/bulk_create_or_update.json", :documents => documents)
|
71
|
+
end
|
72
|
+
def update_document(engine_id, document_type_id, document_id, fields)
|
73
|
+
put("engines/#{engine_id}/document_types/#{document_type_id}/documents/#{document_id}/update_fields.json", { :fields => fields })
|
74
|
+
end
|
75
|
+
def update_documents(engine_id, document_type_id, documents={})
|
76
|
+
put("engines/#{engine_id}/document_types/#{document_type_id}/documents/bulk_update.json", { :documents => documents })
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
include Swiftype::Easy::Engine
|
81
|
+
include Swiftype::Easy::DocumentType
|
82
|
+
include Swiftype::Easy::Document
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Swiftype
|
2
|
+
class Engine < BaseModel
|
3
|
+
def self.find(id)
|
4
|
+
new Swiftype::Client.new.get("engines/#{id}.json")
|
5
|
+
end
|
6
|
+
|
7
|
+
def build_document_type(params={})
|
8
|
+
DocumentType.new({
|
9
|
+
:engine_id => id
|
10
|
+
}.merge(params))
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_document_type(params={})
|
14
|
+
doc = build_document_type(params)
|
15
|
+
doc.create!
|
16
|
+
doc
|
17
|
+
end
|
18
|
+
|
19
|
+
def destroy_document_type(document_type_name)
|
20
|
+
!!delete("engines/#{slug}/document_types/#{document_type_name}")
|
21
|
+
rescue NonExistentRecord
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
def document_type(id)
|
26
|
+
DocumentType.new get("engines/#{slug}/document_types/#{id}.json")
|
27
|
+
end
|
28
|
+
|
29
|
+
def document_types
|
30
|
+
get("engines/#{slug}/document_types.json").map { |dt| DocumentType.new(dt) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module Swiftype
|
2
|
+
class ClientException < StandardError; end
|
3
|
+
class NonExistentRecord < ClientException; end
|
4
|
+
class RecordAlreadyExists < ClientException; end
|
5
|
+
class InvalidCredentials < ClientException; end
|
6
|
+
class UnexpectedHTTPException < ClientException; end
|
7
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Swiftype
|
2
|
+
module Request
|
3
|
+
def get(path, params={}, options={})
|
4
|
+
request(:get, path, params, options)
|
5
|
+
end
|
6
|
+
|
7
|
+
def delete(path, params={}, options={})
|
8
|
+
request(:delete, path, params, options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def post(path, params={}, options={})
|
12
|
+
request(:post, path, params, options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def put(path, params={}, options={})
|
16
|
+
request(:put, path, params, options)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def request(method, path, params, options)
|
21
|
+
params.merge!({:auth_token => Swiftype.api_key}) if Swiftype.api_key
|
22
|
+
response = connection.send(method) do |request|
|
23
|
+
case method.to_sym
|
24
|
+
when :delete, :get
|
25
|
+
request.url(path, params)
|
26
|
+
when :post, :put
|
27
|
+
request.path = path
|
28
|
+
request.body = params unless params.empty?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
options[:raw] ? response : response.body
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Swiftype
|
2
|
+
module Search
|
3
|
+
|
4
|
+
VALID_SEARCH_OPTIONS = [:fetch_fields, :search_fields, :filters, :per_page, :page, :document_types, :functional_boosts]
|
5
|
+
VALID_SUGGEST_OPTIONS = [:fetch_fields, :search_fields, :filters, :document_types, :functional_boosts]
|
6
|
+
|
7
|
+
def parse_search_options(options)
|
8
|
+
parse_options(options,VALID_SEARCH_OPTIONS)
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse_suggest_options(options)
|
12
|
+
parse_options(options,VALID_SUGGEST_OPTIONS)
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse_options(options,valid_options)
|
16
|
+
parsed_options = {}
|
17
|
+
valid_options.each do |option_name|
|
18
|
+
next unless options[option_name]
|
19
|
+
encode_single_option(parsed_options,option_name,options[option_name])
|
20
|
+
end
|
21
|
+
parsed_options
|
22
|
+
end
|
23
|
+
|
24
|
+
# recursive method to encode arrays, hashes, and values the 'Rails' way, to make server-side parsing simpler
|
25
|
+
def encode_single_option(parsed_options,key,value,prefix='')
|
26
|
+
prefix = key if prefix.empty?
|
27
|
+
if value.instance_of?(Hash)
|
28
|
+
value.each { |k,v| encode_single_option(parsed_options,k,v,"#{prefix}[#{k}]") }
|
29
|
+
elsif value.instance_of?(Array)
|
30
|
+
parsed_options["#{prefix}[]"] = value
|
31
|
+
else
|
32
|
+
parsed_options["#{prefix}"] = value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
data/lib/swiftype.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'faraday'
|
3
|
+
require 'faraday_middleware'
|
4
|
+
require 'swiftype/exceptions'
|
5
|
+
|
6
|
+
module Swiftype
|
7
|
+
autoload :Configuration, 'swiftype/configuration'
|
8
|
+
autoload :Connection, 'swiftype/connection'
|
9
|
+
autoload :Client, 'swiftype/client'
|
10
|
+
autoload :BaseModel, 'swiftype/base_model'
|
11
|
+
autoload :Request, 'swiftype/request'
|
12
|
+
autoload :Search, 'swiftype/search'
|
13
|
+
autoload :Engine, 'swiftype/engine'
|
14
|
+
autoload :DocumentType, 'swiftype/document_type'
|
15
|
+
autoload :Document, 'swiftype/document'
|
16
|
+
autoload :Easy, 'swiftype/easy'
|
17
|
+
|
18
|
+
|
19
|
+
extend Configuration
|
20
|
+
|
21
|
+
class << self
|
22
|
+
def new(options={})
|
23
|
+
Swiftype::Client.new(options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_missing(method, *args, &block)
|
27
|
+
return super unless new.respond_to?(method)
|
28
|
+
new.send(method, *args, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def respond_to?(method, include_private=false)
|
32
|
+
new.respond_to?(method, include_private) || super(method, include_private)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
data/swiftype-rb.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "swiftype/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "swiftype-rb"
|
7
|
+
s.version = Swiftype::VERSION
|
8
|
+
s.authors = ["Quin Hoxie", "Matt Riley"]
|
9
|
+
s.email = ["team@swiftype.com"]
|
10
|
+
s.homepage = "http://swiftype.com"
|
11
|
+
s.summary = %q{Swiftype API Gem}
|
12
|
+
s.description = %q{Official Gem for accessing the Swiftype Search API}
|
13
|
+
|
14
|
+
s.rubyforge_project = "swiftype-rb"
|
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 "json"
|
24
|
+
s.add_runtime_dependency "faraday", ['~> 0.7.6']
|
25
|
+
s.add_runtime_dependency "faraday_middleware", ['~> 0.8.4']
|
26
|
+
s.add_runtime_dependency "hashie", ['~> 1.2.0']
|
27
|
+
s.add_runtime_dependency 'activesupport', ['>= 2.3.9', '< 4']
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: swiftype-rb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Quin Hoxie
|
9
|
+
- Matt Riley
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-07-05 00:00:00.000000000Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: json
|
17
|
+
requirement: &70265771944420 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *70265771944420
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: faraday
|
28
|
+
requirement: &70265771943900 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.7.6
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *70265771943900
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: faraday_middleware
|
39
|
+
requirement: &70265771943380 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 0.8.4
|
45
|
+
type: :runtime
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *70265771943380
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: hashie
|
50
|
+
requirement: &70265771942900 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 1.2.0
|
56
|
+
type: :runtime
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *70265771942900
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: activesupport
|
61
|
+
requirement: &70265771942400 !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 2.3.9
|
67
|
+
- - <
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '4'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: *70265771942400
|
73
|
+
description: Official Gem for accessing the Swiftype Search API
|
74
|
+
email:
|
75
|
+
- team@swiftype.com
|
76
|
+
executables: []
|
77
|
+
extensions: []
|
78
|
+
extra_rdoc_files: []
|
79
|
+
files:
|
80
|
+
- .gitignore
|
81
|
+
- Gemfile
|
82
|
+
- README.md
|
83
|
+
- Rakefile
|
84
|
+
- lib/swiftype.rb
|
85
|
+
- lib/swiftype/base_model.rb
|
86
|
+
- lib/swiftype/client.rb
|
87
|
+
- lib/swiftype/configuration.rb
|
88
|
+
- lib/swiftype/connection.rb
|
89
|
+
- lib/swiftype/document.rb
|
90
|
+
- lib/swiftype/document_type.rb
|
91
|
+
- lib/swiftype/easy.rb
|
92
|
+
- lib/swiftype/engine.rb
|
93
|
+
- lib/swiftype/exceptions.rb
|
94
|
+
- lib/swiftype/request.rb
|
95
|
+
- lib/swiftype/search.rb
|
96
|
+
- lib/swiftype/version.rb
|
97
|
+
- swiftype-rb.gemspec
|
98
|
+
homepage: http://swiftype.com
|
99
|
+
licenses: []
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ! '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
requirements: []
|
117
|
+
rubyforge_project: swiftype-rb
|
118
|
+
rubygems_version: 1.8.10
|
119
|
+
signing_key:
|
120
|
+
specification_version: 3
|
121
|
+
summary: Swiftype API Gem
|
122
|
+
test_files: []
|