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.
@@ -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