mode-sdk 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 +17 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +109 -0
- data/Rakefile +6 -0
- data/lib/mode/sdk.rb +70 -0
- data/lib/mode/sdk/client.rb +87 -0
- data/lib/mode/sdk/client/request.rb +133 -0
- data/lib/mode/sdk/client/response.rb +83 -0
- data/lib/mode/sdk/column.rb +95 -0
- data/lib/mode/sdk/column_set.rb +56 -0
- data/lib/mode/sdk/configuration.rb +21 -0
- data/lib/mode/sdk/hash_util.rb +21 -0
- data/lib/mode/sdk/table.rb +168 -0
- data/lib/mode/sdk/table_import.rb +52 -0
- data/lib/mode/sdk/upload.rb +57 -0
- data/lib/mode/sdk/version.rb +9 -0
- data/lib/mode/sdk/warehouse_util.rb +35 -0
- data/mode-sdk.gemspec +27 -0
- data/spec/lib/mode/sdk/client/request_spec.rb +105 -0
- data/spec/lib/mode/sdk/client/response_spec.rb +65 -0
- data/spec/lib/mode/sdk/client_spec.rb +71 -0
- data/spec/lib/mode/sdk/column_set_spec.rb +53 -0
- data/spec/lib/mode/sdk/column_spec.rb +101 -0
- data/spec/lib/mode/sdk/hash_util_spec.rb +18 -0
- data/spec/lib/mode/sdk/table_import_spec.rb +33 -0
- data/spec/lib/mode/sdk/table_spec.rb +191 -0
- data/spec/lib/mode/sdk/upload_spec.rb +37 -0
- data/spec/lib/mode/sdk/warehouse_util_spec.rb +40 -0
- data/spec/lib/mode/sdk_spec.rb +50 -0
- data/spec/spec_helper.rb +17 -0
- metadata +145 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a2fe9f487c0cc04dd360dd4e4439a6d7a9876d95
|
4
|
+
data.tar.gz: 1d23400061905abb0ecec7a45831e3b39f89a5d6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 054cd8e9d9f0c36963b85c7678812d8b60e8baadd8de87e4ccf75b4b5b928e720ea3276ecb1632b3278779852615ef1bf1dbc26035b367310f11604888e02914
|
7
|
+
data.tar.gz: 2f6481aef7a2385992b57841016d8adab0bf5175f8c786325a2b5977a844ff787121a311d1bc329ac5a5d01f8f7b27e3aa80c56ca4475de09c02011e2061c252
|
data/.gitignore
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup=markdown
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Mode Analytics
|
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,109 @@
|
|
1
|
+
# Mode Ruby SDK
|
2
|
+
|
3
|
+
[](https://codeclimate.com/repos/53ea7f57e30ba007c500a24a/feed)
|
4
|
+
|
5
|
+
This SDK provides a wrapper for the [Mode Analytics](https://modeanalytics.com)
|
6
|
+
API.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
gem 'mode-sdk'
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install mode-sdk
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
### Setup
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
Mode::Sdk.configure do |config|
|
28
|
+
config.token = 'token'
|
29
|
+
config.secret = 'secret'
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
You can manage your Mode API tokens here:
|
34
|
+
[https://modeanalytics.com/settings/access_tokens]
|
35
|
+
(https://modeanalytics.com/settings/access_tokens)
|
36
|
+
|
37
|
+
### 1. Upload CSV to Mode
|
38
|
+
|
39
|
+
Before importing a table, you will need to upload the raw CSV (with no header)
|
40
|
+
using the `Upload` class. The first argument can be either a string or an
|
41
|
+
IO-like object.
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
csv = File.open('sf_film_locations.csv', 'r') { |f| f.read }
|
45
|
+
|
46
|
+
upload = Mode::Sdk::Upload.new(csv)
|
47
|
+
upload.create
|
48
|
+
upload.token # => '5b68f4b6a3c6' save this token for step 2
|
49
|
+
```
|
50
|
+
|
51
|
+
Full Upload API documentation:
|
52
|
+
[http://developer.modeanalytics.com/#page:uploads,header:uploads-upload]
|
53
|
+
(http://developer.modeanalytics.com/#page:uploads,header:uploads-upload)
|
54
|
+
|
55
|
+
### 2. Import the table
|
56
|
+
|
57
|
+
Next, initialize a `Table` instance with a name:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
table = Mode::Sdk::Table.new('sf_film_locations')
|
61
|
+
table.exists? # => true, false
|
62
|
+
```
|
63
|
+
|
64
|
+
Assign a column schema (required) and description (optional):
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
table.columns = [
|
68
|
+
{ name: 'movie_title', type: 'string' },
|
69
|
+
{ name: 'release_year', type: 'integer' },
|
70
|
+
{ name: 'location', type: 'string' }
|
71
|
+
]
|
72
|
+
|
73
|
+
table.description = 'Famous film locations in San Francisco'
|
74
|
+
```
|
75
|
+
|
76
|
+
Then use the upload token from Step 1 to create or replace the table:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
table.upload_token = '5b68f4b6a3c6'
|
80
|
+
|
81
|
+
table.create
|
82
|
+
table.replace
|
83
|
+
```
|
84
|
+
|
85
|
+
### 3. Check the status of your import
|
86
|
+
|
87
|
+
The response from `Table#create` or `Table#replace` will indicate the status of
|
88
|
+
your import, including:
|
89
|
+
|
90
|
+
* `enqueued`
|
91
|
+
* `running`
|
92
|
+
* `succeeded`
|
93
|
+
* `failed`
|
94
|
+
|
95
|
+
You can poll this response until your import has completed.
|
96
|
+
|
97
|
+
## Examples
|
98
|
+
|
99
|
+
A collection of examples can be found in the
|
100
|
+
[mode/mode-ruby-examples](https://github.com/mode/mode-ruby-examples)
|
101
|
+
repository.
|
102
|
+
|
103
|
+
## Contributing
|
104
|
+
|
105
|
+
1. Fork it
|
106
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
107
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
108
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
109
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/mode/sdk.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Mode Analytics namespace
|
4
|
+
#
|
5
|
+
module Mode
|
6
|
+
# Official [Mode Analytics](https://modeanalytics.com) Ruby SDK
|
7
|
+
#
|
8
|
+
module Sdk
|
9
|
+
class << self
|
10
|
+
# Set Mode configuration values
|
11
|
+
#
|
12
|
+
# @yield [Mode::Sdk::Configuration] the configuration instance
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# Mode.configure do |config|
|
16
|
+
# config.token = "token"
|
17
|
+
# config.secret = "secret"
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
def configure
|
21
|
+
yield config
|
22
|
+
end
|
23
|
+
|
24
|
+
# The Mode configuration instance
|
25
|
+
#
|
26
|
+
# @return [Mode::Sdk::Configuration] the configuration instance
|
27
|
+
#
|
28
|
+
def config
|
29
|
+
@config ||= Mode::Sdk::Configuration.new
|
30
|
+
end
|
31
|
+
|
32
|
+
# The Mode API representation of the authenticated account
|
33
|
+
#
|
34
|
+
# @return [Hash] the account representation
|
35
|
+
#
|
36
|
+
def account
|
37
|
+
@account ||= Mode::Sdk::Client.account
|
38
|
+
end
|
39
|
+
|
40
|
+
# The username of the authenticated account
|
41
|
+
#
|
42
|
+
# @return [String] the username
|
43
|
+
#
|
44
|
+
def username
|
45
|
+
account.fetch('username')
|
46
|
+
end
|
47
|
+
|
48
|
+
# Un-memoize everything
|
49
|
+
#
|
50
|
+
def reset
|
51
|
+
%w(config account).each do |name|
|
52
|
+
next unless instance_variable_defined?(:"@#{name}")
|
53
|
+
|
54
|
+
remove_instance_variable(:"@#{name}")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
require 'mode/sdk/client'
|
62
|
+
require 'mode/sdk/column'
|
63
|
+
require 'mode/sdk/column_set'
|
64
|
+
require 'mode/sdk/configuration'
|
65
|
+
require 'mode/sdk/hash_util'
|
66
|
+
require 'mode/sdk/table'
|
67
|
+
require 'mode/sdk/table_import'
|
68
|
+
require 'mode/sdk/upload'
|
69
|
+
require 'mode/sdk/version'
|
70
|
+
require 'mode/sdk/warehouse_util'
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'cgi'
|
4
|
+
require 'net/http'
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
module Mode
|
8
|
+
module Sdk
|
9
|
+
# The Client class provides an interface for common Mode API requests
|
10
|
+
#
|
11
|
+
class Client
|
12
|
+
class << self
|
13
|
+
# Make an HTTP HEAD request with the Mode API
|
14
|
+
#
|
15
|
+
# @param path [String] the request path
|
16
|
+
# @param options [optional, Hash] hash of
|
17
|
+
# {Mode::Sdk::Client::Request#initialize request options}
|
18
|
+
#
|
19
|
+
# @return [Mode::Sdk::Client::Response] the response
|
20
|
+
#
|
21
|
+
def head(path, options = {})
|
22
|
+
request(Net::HTTP::Head.new(path), nil, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Make an HTTP GET request with the Mode API
|
26
|
+
#
|
27
|
+
# @param path [String] the request path
|
28
|
+
# @param options [optional, Hash] hash of
|
29
|
+
# {Mode::Sdk::Client::Request#initialize request options}
|
30
|
+
#
|
31
|
+
# @return [Mode::Sdk::Client::Response] the response
|
32
|
+
#
|
33
|
+
def get(path, options = {})
|
34
|
+
request(Net::HTTP::Get.new(path), nil, options)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Make an HTTP POST request with the Mode API
|
38
|
+
#
|
39
|
+
# The body param may be either:
|
40
|
+
#
|
41
|
+
# * a String containing raw CSV, or
|
42
|
+
# * an IO-like object containing the raw CSV for streaming requests
|
43
|
+
#
|
44
|
+
# @param path [String] the request path
|
45
|
+
# @param body [String, #read] the request body
|
46
|
+
# @param options [optional, Hash] hash of
|
47
|
+
# {Mode::Sdk::Client::Request#initialize request options}
|
48
|
+
#
|
49
|
+
# @return [Mode::Sdk::Client::Response] the response
|
50
|
+
#
|
51
|
+
def post(path, body, options = {})
|
52
|
+
request(Net::HTTP::Post.new(path), body, options)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Make an HTTP PUT request with the Mode API
|
56
|
+
#
|
57
|
+
# @param path [String] the request path
|
58
|
+
# @param body [String, #read] the request body
|
59
|
+
# @param options [optional, Hash] hash of
|
60
|
+
# {Mode::Sdk::Client::Request#initialize request options}
|
61
|
+
#
|
62
|
+
# @return [Mode::Sdk::Client::Response] the response
|
63
|
+
#
|
64
|
+
def put(path, body, options = {})
|
65
|
+
request(Net::HTTP::Put.new(path), body, options)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Get the Mode API representation of the authenticated account
|
69
|
+
#
|
70
|
+
# @return [Mode::Sdk::Client::Response] the response
|
71
|
+
#
|
72
|
+
def account
|
73
|
+
get('/api/account', expect: [200]).body
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def request(request, body, options = {})
|
79
|
+
Mode::Sdk::Client::Request.new(request, body, options).response
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
require 'mode/sdk/client/request'
|
87
|
+
require 'mode/sdk/client/response'
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'mode/sdk/version'
|
4
|
+
|
5
|
+
module Mode
|
6
|
+
module Sdk
|
7
|
+
class Client
|
8
|
+
# The Request class wraps a Net::HTTPRequest object for the Mode API
|
9
|
+
#
|
10
|
+
class Request
|
11
|
+
# Construct a new Request instance
|
12
|
+
#
|
13
|
+
# @param http_request [Net::HTTPRequest] the http request
|
14
|
+
# @param body [String, #read] the request body
|
15
|
+
# @param options [optional, Hash] hash of options
|
16
|
+
#
|
17
|
+
# @option options [Array<Integer>] :expect an array of expected
|
18
|
+
# response codes
|
19
|
+
# @option options [String] :content_type the content type of the
|
20
|
+
# request
|
21
|
+
# @option options [Integer] :content_length the content length of the
|
22
|
+
# request
|
23
|
+
#
|
24
|
+
# @return [Mode::Sdk::Client::Request] the instance
|
25
|
+
#
|
26
|
+
def initialize(http_request, body = nil, options = {})
|
27
|
+
@http_request = http_request
|
28
|
+
@body = body
|
29
|
+
@options = options
|
30
|
+
end
|
31
|
+
|
32
|
+
# Result of the HTTP request
|
33
|
+
#
|
34
|
+
# @return [Mode::Sdk::Client::Response] the response
|
35
|
+
#
|
36
|
+
def response
|
37
|
+
http_response = self.class.http.request(build_http_request)
|
38
|
+
|
39
|
+
response = Mode::Sdk::Client::Response.new(
|
40
|
+
http_response, expected_codes)
|
41
|
+
|
42
|
+
response.tap(&:validate!)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
DEFAULT_HOST = 'https://modeanalytics.com'
|
48
|
+
DEFAULT_CONTENT_TYPE = 'application/json'
|
49
|
+
USER_AGENT = "mode-sdk/#{Mode::Sdk::VERSION}"
|
50
|
+
|
51
|
+
attr_reader :http_request, :body, :options
|
52
|
+
|
53
|
+
def build_http_request
|
54
|
+
http_request.tap do
|
55
|
+
assign_basic_auth
|
56
|
+
assign_headers
|
57
|
+
assign_content_meta
|
58
|
+
assign_body
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def assign_basic_auth
|
63
|
+
http_request.basic_auth(*basic_auth)
|
64
|
+
end
|
65
|
+
|
66
|
+
def assign_headers
|
67
|
+
http_request['accept'] = DEFAULT_CONTENT_TYPE
|
68
|
+
http_request['user-agent'] = USER_AGENT
|
69
|
+
end
|
70
|
+
|
71
|
+
def assign_content_meta
|
72
|
+
http_request.content_type = content_type
|
73
|
+
http_request.content_length = content_length if content_length
|
74
|
+
end
|
75
|
+
|
76
|
+
def assign_body
|
77
|
+
case body
|
78
|
+
when nil
|
79
|
+
# no-op
|
80
|
+
when String
|
81
|
+
http_request.body = body
|
82
|
+
else
|
83
|
+
http_request.body_stream = body
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def expected_codes
|
88
|
+
options.fetch(:expect, [])
|
89
|
+
end
|
90
|
+
|
91
|
+
def content_type
|
92
|
+
options.fetch(:content_type, DEFAULT_CONTENT_TYPE)
|
93
|
+
end
|
94
|
+
|
95
|
+
def content_length
|
96
|
+
options.fetch(:content_length, nil)
|
97
|
+
end
|
98
|
+
|
99
|
+
def basic_auth
|
100
|
+
[Mode::Sdk.config.token, Mode::Sdk.config.secret]
|
101
|
+
end
|
102
|
+
|
103
|
+
class << self
|
104
|
+
# The Net::HTTP instance used to make requests
|
105
|
+
#
|
106
|
+
# @return [Net::HTTP] the HTTP instance
|
107
|
+
#
|
108
|
+
def http
|
109
|
+
return @http if defined?(@http)
|
110
|
+
|
111
|
+
@http = Net::HTTP.new(uri.host, uri.port)
|
112
|
+
@http.use_ssl = host =~ /\Ahttps/
|
113
|
+
@http
|
114
|
+
end
|
115
|
+
|
116
|
+
# The Mode API host to use for requests
|
117
|
+
#
|
118
|
+
# @return [String] the API host
|
119
|
+
#
|
120
|
+
def host
|
121
|
+
ENV['MODE_HOST'] || Mode::Sdk.config.host || DEFAULT_HOST
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def uri
|
127
|
+
@uri ||= URI(host)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|