exist 0.1.0.beta.2

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: b0a390bedc2fee545f9ccfded35addeaa8428dcd
4
+ data.tar.gz: 6dcc85f44ae9ff30d6f41049da25243b63d0c85a
5
+ SHA512:
6
+ metadata.gz: d3c73b601bb3ed444f6517d14cfbbf2a294302ef15c8bce42e8aac15a63c2bd7aca42309037af5d83716101a2b6306b9bb7b8f23104d14d98fbd2e602014f955
7
+ data.tar.gz: c164b00cdc918ca9fa03689f72a809d01305d170c9f21d7c62d5dcaf409aba61496fca448ac35db07d43b6319a89c3d851c9ce22c149ed74b60f8115804c1fa2
@@ -0,0 +1,3 @@
1
+ -
2
+ ChangeLog.md
3
+ LICENSE.txt
@@ -0,0 +1,5 @@
1
+ Gemfile.lock
2
+ doc/
3
+ pkg/
4
+ vendor/cache/*.gem
5
+ coverage/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
@@ -0,0 +1 @@
1
+ 2.2.2
@@ -0,0 +1 @@
1
+ --markup markdown --title "exist Documentation" --protected
@@ -0,0 +1,4 @@
1
+ ### 0.1.0 / 2015-06-24
2
+
3
+ * Initial release:
4
+
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'kramdown'
7
+ end
@@ -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.
@@ -0,0 +1,84 @@
1
+ # Exist.IO API Ruby Client
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/exist.png)](http://badge.fury.io/rb/exist) [![Build Status](https://travis-ci.org/blackxored/exist.png)](https://travis-ci.org/blackxored/exist) [![Coverage Status](https://coveralls.io/repos/blackxored/exist/badge.png?branch=master)](https://coveralls.io/r/blackxored/exist) [![Dependency Status](https://gemnasium.com/blackxored/exist.png)](https://gemnasium.com/blackxored/exist) [![Code Climate](https://codeclimate.com/github/blackxored/exist.png)](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
@@ -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
@@ -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
@@ -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'
@@ -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,12 @@
1
+ module Exist
2
+ class AttributeList < Hashie::Mash
3
+ include Hashie::Extensions::Coercion
4
+
5
+ coerce_key :attributes, Array[Attributes]
6
+
7
+ def size
8
+ attributes.size
9
+ end
10
+ alias :count :size
11
+ end
12
+ end
@@ -0,0 +1,4 @@
1
+ module Exist
2
+ class Attributes < Hashie::Mash
3
+ end
4
+ 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
@@ -0,0 +1,4 @@
1
+ module Exist
2
+ class Average < Hashie::Mash
3
+ end
4
+ end
@@ -0,0 +1,11 @@
1
+ module Exist
2
+ class AverageList < Hashie::Mash
3
+ include Hashie::Extensions::Coercion
4
+
5
+ coerce_key :averages, Array[Average]
6
+
7
+ def size
8
+ averages.size
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,4 @@
1
+ module Exist
2
+ class Correlation < Hashie::Mash
3
+ end
4
+ end
@@ -0,0 +1,7 @@
1
+ module Exist
2
+ class CorrelationList < Hashie::Mash
3
+ include Hashie::Extensions::Coercion
4
+
5
+ coerce_key :correlations, Array[Correlation]
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ module Exist
2
+ class Insight < Hashie::Mash
3
+ include Hashie::Extensions::Coercion
4
+
5
+ coerce_key :created, ->(v) { Time.parse(v) }
6
+ coerce_key :target_date, ->(v) { Date.parse(v) }
7
+ end
8
+ end