mode-sdk 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1 @@
1
+ --markup=markdown
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mode-sdk.gemspec
4
+ gemspec
@@ -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.
@@ -0,0 +1,109 @@
1
+ # Mode Ruby SDK
2
+
3
+ [![Code Climate](https://codeclimate.com/repos/53ea7f57e30ba007c500a24a/badges/44f08215be76ea780d56/gpa.svg)](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
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -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