figo 1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3133d62a73507bbdadc5bfc1a4090da15960f895
4
+ data.tar.gz: acb3d79e2d8870dba61f222bc36158050abab8db
5
+ SHA512:
6
+ metadata.gz: 8cb5a5c2ccd4483907c3304c2f842333ee033340f46b1ec23834b8d7c94039cd42fde6f413d7e8ee2a3bed9348722ab6eb63cc2259852ec91fc3152e6aed11c7
7
+ data.tar.gz: 31145565afb3cb72a68bf0705d3b26c31b56ed1595615e218034e33f7f96460fa96f188e966d44088a9713196b17eff9e2a81c0f8a5d78bf30a95e4dc650ca62
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+ Gemfile.lock
15
+
16
+ # YARD artifacts
17
+ .yardoc
18
+ _yardoc
19
+ doc/
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - jruby-19mode # JRuby in 1.9 mode
6
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "rake"
data/README.md ADDED
@@ -0,0 +1,41 @@
1
+ ruby-figo [![Build Status](https://secure.travis-ci.org/figo-connect/ruby-figo.png)](https://travis-ci.org/figo-connect/ruby-figo)
2
+ =========
3
+
4
+ Ruby bindings for the figo connect API: http://figo.me
5
+
6
+ Usage
7
+ =====
8
+
9
+ First, you've to install the gem
10
+
11
+ ```bash
12
+ gem install figo
13
+ ```
14
+
15
+ and require it
16
+
17
+ ```ruby
18
+ require "figo"
19
+ ```
20
+
21
+ Now you can create a new session and access data:
22
+
23
+ ```ruby
24
+ session = Figo::Session.new("ASHWLIkouP2O6_bgA2wWReRhletgWKHYjLqDaqb0LFfamim9RjexTo22ujRIP_cjLiRiSyQXyt2kM1eXU2XLFZQ0Hro15HikJQT_eNeT_9XQ")
25
+
26
+ # Print out a list of accounts.
27
+ session.accounts.each do |account|
28
+ puts account
29
+ puts account.balance
30
+ end
31
+
32
+ # Print out the list of all transactions of a specific account.
33
+ session.get_account("A1.2").transactions.each do |transaction|
34
+ puts transaction
35
+ end
36
+ ```
37
+
38
+ Requirements
39
+ ============
40
+
41
+ This gem requires Ruby 1.9.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc "Run tests"
8
+ task :default => :test
data/figo.gemspec ADDED
@@ -0,0 +1,18 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "figo"
3
+ s.version = "1.0"
4
+ s.authors = ["Stefan Richter", "Michael Haller"]
5
+ s.email = ["stefan.richter@figo.me", "michael.haller@figo.me"]
6
+ s.homepage = "https://github.com/figo-connect/ruby-figo"
7
+ s.license = "MIT"
8
+ s.summary = %q{API wrapper for figo Connect.}
9
+ s.description = %q{Library to easily use the API of http://www.figo.me}
10
+
11
+ s.files = `git ls-files`.split("\n")
12
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
13
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
14
+ s.require_paths = ["lib"]
15
+
16
+ s.add_dependency "flt"
17
+ s.add_dependency "net-http-persistent"
18
+ end
data/lib/figo.rb ADDED
@@ -0,0 +1,243 @@
1
+ #
2
+ # Copyright (c) 2013 figo GmbH
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+
23
+ require "json"
24
+ require "logger"
25
+ require 'net/http/persistent'
26
+ require "digest/sha1"
27
+ require "./lib/models.rb"
28
+
29
+ $logger = Logger.new(STDOUT)
30
+
31
+ module Figo
32
+
33
+ API_ENDPOINT = "api.leanbank.com"
34
+
35
+ VALID_FINGERPRINTS = ["A6:FE:08:F4:A8:86:F9:C1:BF:4E:70:0A:BD:72:AE:B8:8E:B7:78:52",
36
+ "AD:A0:E3:2B:1F:CE:E8:44:F2:83:BA:AE:E4:7D:F2:AD:44:48:7F:1E"]
37
+
38
+ class Error < RuntimeError
39
+
40
+ def initialize(error, error_description) # :nodoc:
41
+ @error = error
42
+ @error_description = error_description
43
+ end
44
+
45
+ def to_s # :nodoc:
46
+ return @error_description
47
+ end
48
+
49
+ end
50
+
51
+ class HTTPS < Net::HTTP::Persistent # :nodoc:
52
+
53
+ def initialize(name = nil, proxy = nil)
54
+ super(name, proxy)
55
+
56
+ # Attribute ca_file must be set, otherwise verify_callback would never be called.
57
+ @ca_file = ""
58
+ @verify_callback = proc do |preverify_ok, store_context|
59
+ if preverify_ok and store_context.error == 0
60
+ certificate = OpenSSL::X509::Certificate.new(store_context.chain[0])
61
+ fingerprint = Digest::SHA1.hexdigest(certificate.to_der).upcase.scan(/../).join(":")
62
+ VALID_FINGERPRINTS.include?(fingerprint)
63
+ else
64
+ false
65
+ end
66
+ end
67
+ end
68
+
69
+ def request(uri, req = nil, &block)
70
+ response = super(uri, req, &block)
71
+
72
+ # Evaluate HTTP response.
73
+ case response
74
+ when Net::HTTPSuccess
75
+ return response
76
+ when Net::HTTPBadRequest
77
+ hash = JSON.parse(response.body)
78
+ raise Error.new(hash["error"], hash["error_description"])
79
+ when Net::HTTPUnauthorized
80
+ raise Error.new("unauthorized", "Missing, invalid or expired access token.")
81
+ when Net::HTTPForbidden
82
+ raise Error.new("forbidden", "Insufficient permission.")
83
+ when Net::HTTPNotFound
84
+ raise Error.new("not_found", "Requested object does not exist.")
85
+ when Net::HTTPMethodNotAllowed
86
+ raise Error.new("method_not_allowed", "Unexpected request method.")
87
+ when Net::HTTPServiceUnavailable
88
+ raise Error.new("service_unavailable", "Exceeded rate limit.")
89
+ else
90
+ $logger.warn("Querying the API failed when accessing '#{path}': #{response.code}")
91
+ raise Error.new("internal_server_error", "We are very sorry, but something went wrong.")
92
+ end
93
+ end
94
+
95
+ end
96
+
97
+ # Represents a non user-bound connection to the figo Connect API.
98
+ class Connection
99
+
100
+ # Create connection object with your client ID and client secret.
101
+ def initialize(client_id, client_secret, redirect_uri = nil)
102
+ @client_id = client_id
103
+ @client_secret = client_secret
104
+ @redirect_uri = redirect_uri
105
+ @https = HTTPS.new("figo-#{client_id}")
106
+ end
107
+
108
+ def query_api(path, data = nil) # :nodoc:
109
+ uri = URI("https://#{API_ENDPOINT}#{path}")
110
+ puts uri
111
+
112
+ # Setup HTTP request.
113
+ request = Net::HTTP::Post.new(path)
114
+ request.basic_auth(@client_id, @client_secret)
115
+ request["Content-Type"] = "application/x-www-form-urlencoded"
116
+ request['User-Agent'] = "ruby-figo"
117
+ request.body = URI.encode_www_form(data) unless data.nil?
118
+
119
+ # Send HTTP request.
120
+ response = @https.request(uri, request)
121
+
122
+ # Evaluate HTTP response.
123
+ return response.body == "" ? {} : JSON.parse(response.body)
124
+ end
125
+
126
+ # Get the URL a user should open in the web browser to start the login process.
127
+ def login_url(state, scope = nil)
128
+ data = { "response_type" => "code", "client_id" => @client_id, "state" => state }
129
+ data["redirect_uri"] = @redirect_uri unless @redirect_uri.nil?
130
+ data["scope"] = scope unless scope.nil?
131
+ return "https://#{API_ENDPOINT}/auth/code?" + URI.encode_www_form(data)
132
+ end
133
+
134
+ # Exchange authorization code or refresh token for access token.
135
+ def obtain_access_token(authorization_code_or_refresh_token, scope = nil)
136
+ # Authorization codes always start with "O" and refresh tokens always start with "R".
137
+ if authorization_code_or_refresh_token[0] == "O"
138
+ data = { "grant_type" => "authorization_code", "code" => authorization_code_or_refresh_token }
139
+ data["redirect_uri"] = @redirect_uri unless @redirect_uri.nil?
140
+ elsif authorization_code_or_refresh_token[0] == "R"
141
+ data = { "grant_type" => "refresh_token", "refresh_token" => authorization_code_or_refresh_token }
142
+ data["scope"] = scope unless scope.nil?
143
+ end
144
+ return query_api("/auth/token", data)
145
+ end
146
+
147
+ # Revoke refresh token or access token.
148
+ def revoke_token(refresh_token_or_access_token)
149
+ data = { "token" => refresh_token_or_access_token }
150
+ query_api("/auth/revoke?" + URI.encode_www_form(data))
151
+ return nil
152
+ end
153
+
154
+ end
155
+
156
+ # Represents a user-bound connection to the figo Connect API and allows access to the user's data.
157
+ class Session
158
+
159
+ # Create session object with access token.
160
+ def initialize(access_token)
161
+ @access_token = access_token
162
+ @https = HTTPS.new("figo-#{access_token}")
163
+ end
164
+
165
+ def query_api(path, data=nil, method="GET") # :nodoc:
166
+ uri = URI("https://#{API_ENDPOINT}#{path}")
167
+
168
+ # Setup HTTP request.
169
+ request = case method
170
+ when "POST"
171
+ Net::HTTP::Post.new(path)
172
+ when "PUT"
173
+ Net::HTTP::Put.new(path)
174
+ when "DELETE"
175
+ Net::HTTP::Delete.new(path)
176
+ else
177
+ Net::HTTP::Get.new(path)
178
+ end
179
+
180
+ request["Authorization"] = "Bearer #{@access_token}"
181
+ request["Content-Type"] = "application/json"
182
+ request['User-Agent'] = "ruby-figo"
183
+ request.body = JSON.generate(data) unless data.nil?
184
+
185
+ # Send HTTP request.
186
+ response = @https.request(uri, request)
187
+
188
+ # Evaluate HTTP response.
189
+ return response.body == "" ? {} : JSON.parse(response.body)
190
+ end
191
+
192
+ # Request list of accounts.
193
+ def accounts
194
+ response = query_api("/rest/accounts")
195
+ return response["accounts"].map {|account| Account.new(self, account)}
196
+ end
197
+
198
+ # Request specific account.
199
+ def get_account(account_id)
200
+ response = query_api("/rest/accounts/#{account_id}")
201
+ return Account.new(self, response)
202
+ end
203
+
204
+ # Request list of transactions.
205
+ def transactions(since = nil, start_id = nil, count = 1000, include_pending = false)
206
+ data = {}
207
+ data["since"] = (since.is_a?(Date) ? since.to_s : since) unless since.nil?
208
+ data["start_id"] = start_id unless start_id.nil?
209
+ data["count"] = count.to_s
210
+ data["include_pending"] = include_pending ? "1" : "0"
211
+ response = query_api("/rest/transactions?" + URI.encode_www_form(data))
212
+ return response["transactions"].map {|transaction| Transaction.new(self, transaction)}
213
+ end
214
+
215
+ # Request the URL a user should open in the web browser to start the synchronization process.
216
+ def sync_url(redirect_uri, state, disable_notifications = false, if_not_synced_since = 0)
217
+ data = { "redirect_uri" => redirect_uri, "state" => state, "disable_notifications" => disable_notifications, "if_not_synced_since" => if_not_synced_since }
218
+ response = query_api("/rest/sync", data, "POST")
219
+ return "https://#{API_ENDPOINT}/task/start?id=#{response["task_token"]}"
220
+ end
221
+
222
+ # Request list of registered notifications.
223
+ def notifications
224
+ response = query_api("/rest/notifications")
225
+ return response["notifications"].map {|notification| Notification.new(self, notification)}
226
+ end
227
+
228
+ # Register notification.
229
+ def add_notification(observe_key, notify_uri, state)
230
+ data = { "observe_key" => observe_key, "notify_uri" => notify_uri, "state" => state }
231
+ response = query_api("/rest/notifications", data, "POST")
232
+ return response["notification_id"]
233
+ end
234
+
235
+ # Unregister notification.
236
+ def remove_notification(notification_id)
237
+ query_api("/rest/notifications/#{notification_id}", nil, "DELETE")
238
+ return nil
239
+ end
240
+
241
+ end
242
+
243
+ end
data/lib/models.rb ADDED
@@ -0,0 +1,161 @@
1
+ #
2
+ # Copyright (c) 2013 figo GmbH
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+
23
+ require "date"
24
+ require "flt"
25
+
26
+ module Figo
27
+
28
+ # Set decimal precision to two digits.
29
+ Flt::DecNum.context.precision = 2
30
+
31
+ class AccountType
32
+ GIRO = "Giro account"
33
+ SAVINGS = "Savings account"
34
+ CREDIT_CARD = "Credit card"
35
+ LOAN = "Loan account"
36
+ PAYPAL = "PayPal"
37
+ UNKNOWN = "Unknown"
38
+ end
39
+
40
+ class TransactionType
41
+ TRANSFER = "Transfer"
42
+ STANDING_ORDER = "Standing order"
43
+ DIRECT_DEBIT = "Direct debit"
44
+ SALARY_OR_RENT = "Salary or rent"
45
+ ELECTRONIC_CASH = "Electronic cash"
46
+ GELDKARTE = "GeldKarte"
47
+ ATM = "ATM"
48
+ CHARGES_OR_INTEREST = "Charges or interest"
49
+ UNKNOWN = "Unknown"
50
+ end
51
+
52
+ class Base # :nodoc:
53
+
54
+ def initialize(session, hash)
55
+ @session = session
56
+
57
+ hash.each do |key, value|
58
+ if key == "status"
59
+ value = SynchronizationStatus.new(session, value)
60
+ elsif key == "amount" or key == "balance"
61
+ value = Flt::DecNum(value.to_s)
62
+ elsif key.end_with?("_date")
63
+ value = DateTime.iso8601(value)
64
+ elsif key.end_with?("_timestamp")
65
+ value = Date.iso8601(value)
66
+ end
67
+ instance_variable_set("@#{key}", value)
68
+ end
69
+ end
70
+
71
+ end
72
+
73
+ class Account < Base
74
+
75
+ attr_accessor :account_id
76
+ attr_accessor :bank_id
77
+ attr_accessor :name
78
+ attr_accessor :owner
79
+ attr_accessor :auto_sync
80
+ attr_accessor :account_number
81
+ attr_accessor :bank_code
82
+ attr_accessor :bank_name
83
+ attr_accessor :currency
84
+ attr_accessor :iban
85
+ attr_accessor :bic
86
+ attr_accessor :type
87
+ attr_accessor :icon
88
+ attr_accessor :in_total_balance
89
+ attr_accessor :preview
90
+ attr_accessor :status
91
+
92
+ # Request balance.
93
+ def balance
94
+ response = @session.query_api("/rest/accounts/#{@account_id}/balance")
95
+ return AccountBalance.new(@session, response)
96
+ end
97
+
98
+ # Request list of transactions.
99
+ def transactions(since = nil, start_id = nil, count = 1000, include_pending = false)
100
+ data = {}
101
+ data["since"] = (since.is_a?(Date) ? since.to_s : since) unless since.nil?
102
+ data["start_id"] = start_id unless start_id.nil?
103
+ data["count"] = count.to_s
104
+ data["include_pending"] = include_pending ? "1" : "0"
105
+ response = @session.query_api("/rest/accounts/#{@account_id}/transactions?" + URI.encode_www_form(data))
106
+ return response["transactions"].map {|transaction| Transaction.new(@session, transaction)}
107
+ end
108
+
109
+ end
110
+
111
+ class AccountBalance < Base
112
+
113
+ attr_accessor :balance
114
+ attr_accessor :balance_date
115
+ attr_accessor :credit_line
116
+ attr_accessor :monthly_spending_limit
117
+ attr_accessor :status
118
+
119
+ end
120
+
121
+ class Transaction < Base
122
+
123
+ attr_accessor :transaction_id
124
+ attr_accessor :account_id
125
+ attr_accessor :name
126
+ attr_accessor :account_number
127
+ attr_accessor :bank_code
128
+ attr_accessor :bank_name
129
+ attr_accessor :amount
130
+ attr_accessor :currency
131
+ attr_accessor :booking_date
132
+ attr_accessor :value_date
133
+ attr_accessor :purpose
134
+ attr_accessor :type
135
+ attr_accessor :booking_text
136
+ attr_accessor :booked
137
+ attr_accessor :creation_timestamp
138
+ attr_accessor :modification_timestamp
139
+ attr_accessor :visited
140
+
141
+ end
142
+
143
+ class SynchronizationStatus < Base
144
+
145
+ attr_accessor :code
146
+ attr_accessor :message
147
+ attr_accessor :sync_timestamp
148
+ attr_accessor :success_timestamp
149
+
150
+ end
151
+
152
+ class Notification < Base
153
+
154
+ attr_accessor :notification_id
155
+ attr_accessor :observe_key
156
+ attr_accessor :notify_uri
157
+ attr_accessor :state
158
+
159
+ end
160
+
161
+ end
data/test/test_figo.rb ADDED
@@ -0,0 +1,28 @@
1
+ #
2
+ # Copyright (c) 2013 figo GmbH
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #
22
+
23
+ require "test/unit"
24
+ require "figo"
25
+
26
+ class FigoTest < Test::Unit::TestCase
27
+
28
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: figo
3
+ version: !ruby/object:Gem::Version
4
+ version: "1.0"
5
+ platform: ruby
6
+ authors:
7
+ - Stefan Richter
8
+ - Michael Haller
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2013-06-04 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: flt
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - &id002
21
+ - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ type: :runtime
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: net-http-persistent
28
+ prerelease: false
29
+ requirement: &id003 !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - *id002
32
+ type: :runtime
33
+ version_requirements: *id003
34
+ description: Library to easily use the API of http://www.figo.me
35
+ email:
36
+ - stefan.richter@figo.me
37
+ - michael.haller@figo.me
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files: []
43
+
44
+ files:
45
+ - .gitignore
46
+ - .travis.yml
47
+ - Gemfile
48
+ - README.md
49
+ - Rakefile
50
+ - figo.gemspec
51
+ - lib/figo.rb
52
+ - lib/models.rb
53
+ - test/test_figo.rb
54
+ homepage: https://github.com/figo-connect/ruby-figo
55
+ licenses:
56
+ - MIT
57
+ metadata: {}
58
+
59
+ post_install_message:
60
+ rdoc_options: []
61
+
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - *id002
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - *id002
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 2.0.3
74
+ signing_key:
75
+ specification_version: 4
76
+ summary: API wrapper for figo Connect.
77
+ test_files:
78
+ - test/test_figo.rb