exist 0.1.0.beta.2
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/.document +3 -0
- data/.gitignore +5 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +4 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +20 -0
- data/README.md +84 -0
- data/Rakefile +34 -0
- data/exist.gemspec +33 -0
- data/lib/exist.rb +16 -0
- data/lib/exist/api.rb +122 -0
- data/lib/exist/attribute_list.rb +12 -0
- data/lib/exist/attributes.rb +4 -0
- data/lib/exist/authentication.rb +25 -0
- data/lib/exist/average.rb +4 -0
- data/lib/exist/average_list.rb +11 -0
- data/lib/exist/correlation.rb +4 -0
- data/lib/exist/correlation_list.rb +7 -0
- data/lib/exist/insight.rb +8 -0
- data/lib/exist/insight_list.rb +11 -0
- data/lib/exist/user.rb +8 -0
- data/lib/exist/version.rb +3 -0
- data/spec/exist/api_spec.rb +238 -0
- data/spec/exist_spec.rb +7 -0
- data/spec/fixtures/attributes.json +47 -0
- data/spec/fixtures/average_for_specific_attribute.json +31 -0
- data/spec/fixtures/averages.json +26 -0
- data/spec/fixtures/correlations.json +27 -0
- data/spec/fixtures/insights.json +51 -0
- data/spec/fixtures/insights_for_specific_attribute.json +29 -0
- data/spec/fixtures/overview.json +41 -0
- data/spec/fixtures/specific_attribute.json +29 -0
- data/spec/fixtures/user_stripped.json +13 -0
- data/spec/spec_helper.rb +42 -0
- data/spec/support/api_helpers.rb +20 -0
- metadata +275 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b0a390bedc2fee545f9ccfded35addeaa8428dcd
|
4
|
+
data.tar.gz: 6dcc85f44ae9ff30d6f41049da25243b63d0c85a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d3c73b601bb3ed444f6517d14cfbbf2a294302ef15c8bce42e8aac15a63c2bd7aca42309037af5d83716101a2b6306b9bb7b8f23104d14d98fbd2e602014f955
|
7
|
+
data.tar.gz: c164b00cdc918ca9fa03689f72a809d01305d170c9f21d7c62d5dcaf409aba61496fca448ac35db07d43b6319a89c3d851c9ce22c149ed74b60f8115804c1fa2
|
data/.document
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour --format documentation
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.2.2
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown --title "exist Documentation" --protected
|
data/ChangeLog.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2015 Adrian Perez
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# Exist.IO API Ruby Client
|
2
|
+
|
3
|
+
[](http://badge.fury.io/rb/exist) [](https://travis-ci.org/blackxored/exist) [](https://coveralls.io/r/blackxored/exist) [](https://gemnasium.com/blackxored/exist) [](https://codeclimate.com/github/blackxored/exist)
|
4
|
+
|
5
|
+
## Disclaimer
|
6
|
+
|
7
|
+
Please notice that the Exist.IO API is experimental as noticed by their
|
8
|
+
developers, so it's this library by extension, I'm not affiliated with the Exist
|
9
|
+
development team, I'm just another user of the platform addicted to the
|
10
|
+
quantified-self concept ;)
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
gem 'exist'
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
$ bundle
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
$ gem install exist
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
### Authentication
|
29
|
+
|
30
|
+
All (if not most) requests require authentication. Exist uses a non-expiring
|
31
|
+
token that you can configure this client with. It also supports username
|
32
|
+
and password login, although I'd recommend not to store this and use
|
33
|
+
the token instead.
|
34
|
+
|
35
|
+
You can login with username & password:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
|
39
|
+
exist = Exist::API.new(username: 'youruser', password: 'yourpass')
|
40
|
+
```
|
41
|
+
|
42
|
+
Then retrieve the token:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
exist.api_key
|
46
|
+
```
|
47
|
+
|
48
|
+
You can store it somewhere safe, it will try to read from the `EXIST_API_TOKEN`
|
49
|
+
environment variable if you initialize the client without options. You can also
|
50
|
+
pass it directly, as you would have expected:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
Exist::API.new(token: "<YOUR_TOKEN>")
|
54
|
+
```
|
55
|
+
|
56
|
+
### Data methods
|
57
|
+
|
58
|
+
From then on, you have access to all of the current endpoints (more
|
59
|
+
information in the [developer's site](http://developer.exist.io/)),
|
60
|
+
through the client instance:
|
61
|
+
|
62
|
+
* The current user (`#me`).
|
63
|
+
* Overviews (i.e. Today view) (`#overview`).
|
64
|
+
* Attributes (`#attributes`, `#attribute`).
|
65
|
+
* Insights (`#insights`, `#insights_for_attribute`).
|
66
|
+
* Averages (`#averages`, `#averages_for_attribute`).
|
67
|
+
* Correlations (`#correlations`).
|
68
|
+
|
69
|
+
Notice that most endpoints can only be used with the current user,
|
70
|
+
hence they don't ask for username, I will update this in the future
|
71
|
+
if this changes.
|
72
|
+
|
73
|
+
## Roadmap
|
74
|
+
|
75
|
+
I intent to make this gem more AR-friendly, with finders, queries, deep search,
|
76
|
+
to fill the gaps from the API itself.
|
77
|
+
|
78
|
+
## Contributing
|
79
|
+
|
80
|
+
1. Fork it ( https://github.com/blackxored/exist/fork )
|
81
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
82
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
83
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
84
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'bundler'
|
7
|
+
rescue LoadError => e
|
8
|
+
warn e.message
|
9
|
+
warn "Run `gem install bundler` to install Bundler."
|
10
|
+
exit -1
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
Bundler.setup(:development)
|
15
|
+
rescue Bundler::BundlerError => e
|
16
|
+
warn e.message
|
17
|
+
warn "Run `bundle install` to install missing gems."
|
18
|
+
exit e.status_code
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake'
|
22
|
+
|
23
|
+
require 'rubygems/tasks'
|
24
|
+
Gem::Tasks.new
|
25
|
+
|
26
|
+
require 'rspec/core/rake_task'
|
27
|
+
RSpec::Core::RakeTask.new
|
28
|
+
|
29
|
+
task :test => :spec
|
30
|
+
task :default => :spec
|
31
|
+
|
32
|
+
require 'yard'
|
33
|
+
YARD::Rake::YardocTask.new
|
34
|
+
task :doc => :yard
|
data/exist.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require File.expand_path('../lib/exist/version', __FILE__)
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = "exist"
|
7
|
+
gem.version = Exist::VERSION
|
8
|
+
gem.summary = "Ruby client for the Exist.IO API"
|
9
|
+
gem.description = %q{Ruby client for the Exist.IO life-tracking/correlation platform API}
|
10
|
+
gem.license = "MIT"
|
11
|
+
gem.authors = ["Adrian Perez"]
|
12
|
+
gem.email = "adrianperez.deb@gmail.com"
|
13
|
+
gem.homepage = "https://github.com/blackxored/exist"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ['lib']
|
19
|
+
|
20
|
+
gem.add_dependency 'faraday', '~> 0.9'
|
21
|
+
gem.add_dependency 'faraday_middleware', '~> 0.9'
|
22
|
+
gem.add_dependency 'hashie', '~> 3.4'
|
23
|
+
gem.add_development_dependency 'bundler', '~> 1.0'
|
24
|
+
gem.add_development_dependency 'rake', '~> 0.8'
|
25
|
+
gem.add_development_dependency 'rspec', '~> 2.4'
|
26
|
+
gem.add_development_dependency 'webmock', '>= 1.21.0'
|
27
|
+
gem.add_development_dependency 'simplecov', '>= 0.10.0'
|
28
|
+
gem.add_development_dependency 'coveralls', '>= 0.8.2'
|
29
|
+
gem.add_development_dependency 'rubocop', '>= 0.32.1 '
|
30
|
+
gem.add_development_dependency 'rubygems-tasks', '~> 0.2'
|
31
|
+
gem.add_development_dependency 'yard', '~> 0.8'
|
32
|
+
gem.add_development_dependency 'pry', '>= 0.10.1'
|
33
|
+
end
|
data/lib/exist.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
require 'hashie'
|
4
|
+
|
5
|
+
require 'exist/version'
|
6
|
+
require 'exist/authentication'
|
7
|
+
require 'exist/attributes'
|
8
|
+
require 'exist/attribute_list'
|
9
|
+
require 'exist/insight'
|
10
|
+
require 'exist/insight_list'
|
11
|
+
require 'exist/average'
|
12
|
+
require 'exist/average_list'
|
13
|
+
require 'exist/correlation'
|
14
|
+
require 'exist/correlation_list'
|
15
|
+
require 'exist/user'
|
16
|
+
require 'exist/api'
|
data/lib/exist/api.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
module Exist
|
2
|
+
class API
|
3
|
+
include Authentication
|
4
|
+
|
5
|
+
attr_reader :client
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@options = options
|
9
|
+
@token = options[:token]
|
10
|
+
@client = initialize_http_client
|
11
|
+
|
12
|
+
login! if credentials_provided?
|
13
|
+
|
14
|
+
unless api_key
|
15
|
+
raise ArgumentError.new(
|
16
|
+
"Must include user & password if no token provided or in environment"
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
client.headers['Authorization'] = "Token #{api_key}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def me
|
24
|
+
User.new(client.get('users/$self/').body)
|
25
|
+
end
|
26
|
+
|
27
|
+
def overview(username = '$self')
|
28
|
+
User.new(client.get("users/#{username}/today/").body)
|
29
|
+
end
|
30
|
+
|
31
|
+
def attributes(limit: 31)
|
32
|
+
response = client.get('users/$self/attributes/', limit: limit).body
|
33
|
+
|
34
|
+
AttributeList.new(attributes: response)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Date format is YYYY-mm-dd
|
38
|
+
def attribute(attribute, limit: 31, page: 1, oldest_date: nil, newest_date: nil)
|
39
|
+
response = client.get(
|
40
|
+
"users/$self/attributes/#{attribute}/",
|
41
|
+
page: page, limit: limit, date_min: oldest_date, date_max: newest_date
|
42
|
+
).body
|
43
|
+
AttributeList.new(
|
44
|
+
attributes: response['results'],
|
45
|
+
total: response['count'],
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
def insights(limit: 31, page: 1, oldest_date: nil, newest_date: nil)
|
50
|
+
response = client.get(
|
51
|
+
"users/$self/insights/",
|
52
|
+
page: page, limit: limit, date_min: oldest_date, date_max: newest_date
|
53
|
+
)
|
54
|
+
|
55
|
+
InsightList.new(
|
56
|
+
insights: response.body['results'],
|
57
|
+
total: response.body['count'],
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
def insights_for_attribute(attribute, limit: 31, page: 1, oldest_date: nil, newest_date: nil)
|
62
|
+
response = client.get(
|
63
|
+
"users/$self/insights/attribute/#{attribute}/",
|
64
|
+
page: page, limit: limit, date_min: oldest_date, date_max: newest_date
|
65
|
+
)
|
66
|
+
InsightList.new(
|
67
|
+
insights: response.body['results'],
|
68
|
+
total: response.body['count'],
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
def averages
|
73
|
+
response = client.get('users/$self/averages/')
|
74
|
+
AverageList.new(averages: response.body)
|
75
|
+
end
|
76
|
+
|
77
|
+
def average_for_attribute(attribute, limit: 31, page: 1, oldest_date: nil, newest_date: nil)
|
78
|
+
response = client.get(
|
79
|
+
"users/$self/averages/attribute/#{attribute}/",
|
80
|
+
page: page, limit: limit, date_min: oldest_date, date_max: newest_date
|
81
|
+
).body
|
82
|
+
|
83
|
+
AverageList.new(averages: response['results'], total: response['count'])
|
84
|
+
end
|
85
|
+
|
86
|
+
def correlations(username, attribute,
|
87
|
+
limit: 31, page: 1, oldest_date: nil, newest_date: nil,
|
88
|
+
latest_only: false)
|
89
|
+
|
90
|
+
params = { page: page, limit: limit }
|
91
|
+
if !latest_only
|
92
|
+
params.merge!(date_min: oldest_date, date_max: newest_date)
|
93
|
+
else
|
94
|
+
params.merge!(latest_only: true)
|
95
|
+
end
|
96
|
+
|
97
|
+
response = client.get(
|
98
|
+
"users/#{username}/correlations/attribute/#{attribute}/", params
|
99
|
+
).body
|
100
|
+
|
101
|
+
CorrelationList.new(
|
102
|
+
correlations: response['results'],
|
103
|
+
total: response['count']
|
104
|
+
)
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
def initialize_http_client
|
109
|
+
Faraday.new(url: base_url) do |conn|
|
110
|
+
conn.headers['User-Agent'] = "Exist Ruby #{Exist::VERSION}"
|
111
|
+
conn.request :json
|
112
|
+
conn.response :logger if ENV['FARADAY_DEBUG']
|
113
|
+
conn.response :json, content_type: /\bjson$/
|
114
|
+
conn.adapter Faraday.default_adapter
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def base_url
|
119
|
+
'https://exist.io/api/1/'
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Exist
|
2
|
+
module Authentication
|
3
|
+
def api_key
|
4
|
+
@token || ENV['EXIST_API_TOKEN']
|
5
|
+
end
|
6
|
+
|
7
|
+
def login!
|
8
|
+
resp = client.post(
|
9
|
+
'auth/simple-token',
|
10
|
+
username: @options[:username],
|
11
|
+
password: @options[:password]
|
12
|
+
)
|
13
|
+
|
14
|
+
if resp.body && resp.body['token']
|
15
|
+
@token = resp.body['token']
|
16
|
+
else
|
17
|
+
raise 'There was a problem authenticating with the API'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def credentials_provided?
|
22
|
+
@options[:username] && @options[:password]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|