finapps 0.0.14.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +3 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +22 -0
- data/README.md +64 -0
- data/Rakefile +2 -0
- data/bin/finapps +6 -0
- data/finapps.gemspec +35 -0
- data/lib/finapps/cli/common.rb +40 -0
- data/lib/finapps/cli/institutions.rb +34 -0
- data/lib/finapps/cli/users.rb +87 -0
- data/lib/finapps/middleware/api_token.rb +25 -0
- data/lib/finapps/middleware/raise_http_exceptions.rb +91 -0
- data/lib/finapps/middleware/response_logger.rb +40 -0
- data/lib/finapps/rest/accounts.rb +13 -0
- data/lib/finapps/rest/client.rb +154 -0
- data/lib/finapps/rest/connection.rb +77 -0
- data/lib/finapps/rest/defaults.rb +36 -0
- data/lib/finapps/rest/errors.rb +110 -0
- data/lib/finapps/rest/institutions.rb +32 -0
- data/lib/finapps/rest/resource.rb +13 -0
- data/lib/finapps/rest/resources.rb +17 -0
- data/lib/finapps/rest/users.rb +45 -0
- data/lib/finapps/utils/logging.rb +78 -0
- data/lib/finapps/utils/utils.rb +51 -0
- data/lib/finapps/version.rb +3 -0
- data/lib/finapps.rb +25 -0
- data/spec/rest/client_spec.rb +61 -0
- data/spec/spec_helper.rb +84 -0
- metadata +246 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'pp'
|
2
|
+
|
3
|
+
module FinApps
|
4
|
+
module REST
|
5
|
+
module Connection
|
6
|
+
include FinApps::REST::Defaults
|
7
|
+
|
8
|
+
# @param [Hash] company_credentials
|
9
|
+
# @param [Hash] config
|
10
|
+
# @return [Faraday::Connection]
|
11
|
+
def set_up_connection(company_credentials, config)
|
12
|
+
logger.debug "##{__method__.to_s} => Started"
|
13
|
+
|
14
|
+
company_credentials.validate_required_strings!
|
15
|
+
logger.debug "##{__method__.to_s} => company_credentials passed validation."
|
16
|
+
|
17
|
+
host = config[:host]
|
18
|
+
validate_host_url! host
|
19
|
+
|
20
|
+
base_url = "#{host}/v#{API_VERSION}"
|
21
|
+
logger.debug " base_url: #{base_url}"
|
22
|
+
|
23
|
+
timeout = config[:timeout].blank? ? DEFAULTS[:timeout] : config[:timeout]
|
24
|
+
logger.debug " timeout: #{timeout}"
|
25
|
+
|
26
|
+
user_identifier = config[:user_identifier]
|
27
|
+
logger.debug " user_identifier: #{user_identifier}" if user_identifier.present?
|
28
|
+
|
29
|
+
user_token = config[:user_token]
|
30
|
+
logger.debug ' user_token: [REDACTED]' if user_token.present?
|
31
|
+
|
32
|
+
connection = Faraday.new(:url => base_url,
|
33
|
+
:request => {
|
34
|
+
:open_timeout => timeout,
|
35
|
+
:timeout => timeout},
|
36
|
+
:headers => {
|
37
|
+
:accept => HEADERS[:accept],
|
38
|
+
:user_agent => HEADERS[:user_agent]}) do |conn|
|
39
|
+
|
40
|
+
# Request Middleware
|
41
|
+
conn.use FinApps::Middleware::ApiToken, company_credentials
|
42
|
+
conn.request :json
|
43
|
+
conn.request :retry
|
44
|
+
conn.request :multipart
|
45
|
+
conn.request :url_encoded
|
46
|
+
if user_identifier.blank? || user_token.blank?
|
47
|
+
logger.debug "##{__method__.to_s} => User credentials were not provided. Authentication header not set."
|
48
|
+
else
|
49
|
+
conn.request :basic_auth, user_identifier, user_token
|
50
|
+
logger.debug "##{__method__.to_s} => Basic Authentication header set for provided user credentials."
|
51
|
+
end
|
52
|
+
|
53
|
+
# Response Middleware
|
54
|
+
conn.use FinApps::Middleware::RaiseHttpExceptions
|
55
|
+
conn.response :rashify
|
56
|
+
conn.response :json, :content_type => /\bjson$/
|
57
|
+
conn.use FinApps::Middleware::ResponseLogger
|
58
|
+
|
59
|
+
# Adapter (ensure that the adapter is always last.)
|
60
|
+
conn.adapter :typhoeus
|
61
|
+
end
|
62
|
+
|
63
|
+
logger.debug "##{__method__.to_s} => Completed"
|
64
|
+
connection
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
def validate_host_url!(host_url)
|
69
|
+
raise MissingArgumentsError.new 'Missing argument: host_url.' if host_url.blank?
|
70
|
+
raise InvalidArgumentsError.new 'Invalid argument: host_url does not specify a valid protocol (http/https).' unless host_url.start_with?('http://', 'https://')
|
71
|
+
|
72
|
+
logger.debug "##{__method__.to_s} => host [#{host_url}] passed validation."
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module FinApps
|
2
|
+
module REST
|
3
|
+
module Defaults
|
4
|
+
|
5
|
+
API_VERSION = '1'
|
6
|
+
|
7
|
+
HEADERS = {
|
8
|
+
:accept => 'application/json',
|
9
|
+
:user_agent => "finapps-ruby/#{FinApps::VERSION} (#{RUBY_ENGINE}/#{RUBY_PLATFORM} #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL})"
|
10
|
+
}
|
11
|
+
|
12
|
+
# noinspection SpellCheckingInspection
|
13
|
+
DEFAULTS = {
|
14
|
+
:host => 'https://www.financialapps.com',
|
15
|
+
:timeout => 30,
|
16
|
+
:proxy_addr => nil,
|
17
|
+
:proxy_port => nil,
|
18
|
+
:proxy_user => nil,
|
19
|
+
:proxy_pass => nil,
|
20
|
+
:retry_limit => 1,
|
21
|
+
:log_level => Logger::INFO
|
22
|
+
}
|
23
|
+
|
24
|
+
|
25
|
+
END_POINTS = {
|
26
|
+
:users_create => 'users/new',
|
27
|
+
:users_login => 'users/login',
|
28
|
+
:users_delete => 'users/:public_id/delete',
|
29
|
+
:institutions_search => 'institutions/:search_term/search',
|
30
|
+
:institutions_form => 'institutions/:site_id/form',
|
31
|
+
:institutions_add => 'institutions/:site_id/add',
|
32
|
+
}
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module FinApps
|
2
|
+
module REST
|
3
|
+
|
4
|
+
# Custom error class for rescuing from all FinApps errors
|
5
|
+
class Error < StandardError;
|
6
|
+
attr_reader :response
|
7
|
+
|
8
|
+
def initialize(ex, response = nil)
|
9
|
+
@wrapped_exception = nil
|
10
|
+
@response = response
|
11
|
+
|
12
|
+
if ex.respond_to?(:backtrace)
|
13
|
+
super(ex.message)
|
14
|
+
@wrapped_exception = ex
|
15
|
+
elsif ex.respond_to?(:each_key)
|
16
|
+
super("the server responded with status #{ex[:status]}")
|
17
|
+
@response = ex
|
18
|
+
else
|
19
|
+
super(ex.to_s)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def backtrace
|
24
|
+
if @wrapped_exception
|
25
|
+
@wrapped_exception.backtrace
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def inspect
|
32
|
+
%(#<#{self.class}>)
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [Array<String>]
|
36
|
+
def error_messages
|
37
|
+
@response.present? ? @response[:error_messages] : []
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
# Raised when required arguments are missing
|
43
|
+
class MissingArgumentsError < Error
|
44
|
+
def initialize(message)
|
45
|
+
super(message)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Raised when invalid arguments are detected
|
50
|
+
class InvalidArgumentsError < Error
|
51
|
+
def initialize(message)
|
52
|
+
super(message)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
# Client Error 4xx
|
58
|
+
# The 4xx class of status code is intended for cases in which the client seems to have erred.
|
59
|
+
class ClientError < Error
|
60
|
+
end
|
61
|
+
|
62
|
+
class BadRequest < ClientError
|
63
|
+
end
|
64
|
+
|
65
|
+
class Unauthorized < ClientError
|
66
|
+
end
|
67
|
+
|
68
|
+
class Forbidden < ClientError
|
69
|
+
end
|
70
|
+
|
71
|
+
class NotFound < ClientError
|
72
|
+
end
|
73
|
+
|
74
|
+
class MethodNotAllowed < ClientError
|
75
|
+
end
|
76
|
+
|
77
|
+
class NotAcceptable < ClientError
|
78
|
+
end
|
79
|
+
|
80
|
+
class ConnectionFailed < ClientError
|
81
|
+
end
|
82
|
+
|
83
|
+
class Conflict < ClientError
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
# Server Error 5xx
|
88
|
+
#
|
89
|
+
# Response status codes beginning with the digit "5" indicate cases in which the server is aware
|
90
|
+
# that it has erred or is incapable of performing the request.
|
91
|
+
class ServerError < Error
|
92
|
+
end
|
93
|
+
|
94
|
+
class InternalServerError < ServerError
|
95
|
+
end
|
96
|
+
|
97
|
+
class BadGateway < ServerError
|
98
|
+
end
|
99
|
+
|
100
|
+
class ServiceUnavailable < ServerError
|
101
|
+
end
|
102
|
+
|
103
|
+
class GatewayTimeout < ServerError
|
104
|
+
end
|
105
|
+
|
106
|
+
class VersionNotSupported < ServerError
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module FinApps
|
2
|
+
module REST
|
3
|
+
|
4
|
+
class Institutions < FinApps::REST::Resources
|
5
|
+
|
6
|
+
# @param [String] term
|
7
|
+
# @return [Array<FinApps::REST::Institution>, Array<String>]
|
8
|
+
def search(term)
|
9
|
+
logger.debug "##{__method__.to_s} => Started"
|
10
|
+
|
11
|
+
raise MissingArgumentsError.new 'Missing argument: term.' if term.blank?
|
12
|
+
logger.debug "##{__method__.to_s} => term: #{term}"
|
13
|
+
|
14
|
+
path = END_POINTS[:institutions_search].sub! ':search_term', term.to_s
|
15
|
+
|
16
|
+
institutions, error_messages = @client.get(path) do |r|
|
17
|
+
r.body.each { |i| Institution.new(i) }
|
18
|
+
end
|
19
|
+
|
20
|
+
logger.debug "##{__method__.to_s} => Completed"
|
21
|
+
return institutions, error_messages
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
class Institution < FinApps::REST::Resource
|
28
|
+
attr_accessor :base_url, :display_name, :site_id, :org_display_name
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module FinApps
|
2
|
+
module REST
|
3
|
+
class Resources
|
4
|
+
|
5
|
+
include FinApps::REST::Defaults
|
6
|
+
include FinApps::Logging
|
7
|
+
|
8
|
+
# @param [FinApps::REST::Client] client
|
9
|
+
# @return [FinApps::REST::Resources]
|
10
|
+
def initialize(client)
|
11
|
+
@client = client
|
12
|
+
logger.debug "##{__method__.to_s} => #{self.class.name} initialized."
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module FinApps
|
2
|
+
module REST
|
3
|
+
|
4
|
+
class Users < FinApps::REST::Resources
|
5
|
+
include FinApps::Logging
|
6
|
+
|
7
|
+
# @param [Hash] params
|
8
|
+
# @return [FinApps::REST::User, Array<String>]
|
9
|
+
def create(params = {})
|
10
|
+
logger.debug "##{__method__.to_s} => Started"
|
11
|
+
user, error_messages = @client.post(END_POINTS[:users_create], params) { |r| User.new(r.body) }
|
12
|
+
logger.debug "##{__method__.to_s} => Completed"
|
13
|
+
|
14
|
+
return user, error_messages
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param [Hash] params
|
18
|
+
# @return [FinApps::REST::User, Array<String>]
|
19
|
+
def login(params = {})
|
20
|
+
logger.debug "##{__method__.to_s} => Started"
|
21
|
+
user, error_messages = @client.post(END_POINTS[:users_login], params) { |r| User.new(r.body) }
|
22
|
+
logger.debug "##{__method__.to_s} => Completed"
|
23
|
+
|
24
|
+
return user, error_messages
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param [String] public_id
|
28
|
+
# @return [Array<String>]
|
29
|
+
def delete(public_id)
|
30
|
+
logger.debug "##{__method__.to_s} => Started"
|
31
|
+
raise MissingArgumentsError.new 'Missing argument: public_id.' if public_id.blank?
|
32
|
+
_, error_messages = @client.delete(END_POINTS[:users_delete].sub! ':public_id', public_id.to_s)
|
33
|
+
logger.debug "##{__method__.to_s} => Completed"
|
34
|
+
|
35
|
+
error_messages
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
class User < FinApps::REST::Resource
|
41
|
+
attr_accessor :public_id, :token, :email, :first_name, :last_name, :postal_code
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module FinApps
|
2
|
+
module Logging
|
3
|
+
|
4
|
+
SEVERITY_LABEL = %w(DEBUG INFO WARN ERROR FATAL UNKNOWN)
|
5
|
+
PROTECTED_KEYS = [:password, :password_confirm]
|
6
|
+
|
7
|
+
class << self;
|
8
|
+
attr_accessor :tag;
|
9
|
+
end
|
10
|
+
|
11
|
+
def logger=(logger)
|
12
|
+
@logger = logger
|
13
|
+
end
|
14
|
+
|
15
|
+
# noinspection SpellCheckingInspection
|
16
|
+
def logger
|
17
|
+
|
18
|
+
@logger ||= begin
|
19
|
+
require 'logger' unless defined?(::Logger)
|
20
|
+
::Logger.new(STDOUT).tap do |log|
|
21
|
+
log.progname = "#{self.class.to_s}"
|
22
|
+
log.formatter = proc do |severity, time, progname, msg|
|
23
|
+
Logging.tag.present? ?
|
24
|
+
"[%s#%d] %5s -- %s: %s %s\n" % [format_datetime(time), $$, severity, progname, Logging.tag.to_s, msg2str(msg)] :
|
25
|
+
"[%s#%d] %5s -- %s: %s\n" % [format_datetime(time), $$, severity, progname, msg2str(msg)]
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_up_logger_level(logger_level)
|
34
|
+
unless logger_level.blank? || @logger.level == logger_level
|
35
|
+
@logger.info "##{__method__.to_s} => Setting logger level to #{SEVERITY_LABEL[logger_level]}"
|
36
|
+
@logger.level = logger_level
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# noinspection SpellCheckingInspection
|
41
|
+
def set_up_logger_session_params(uuid, session_id)
|
42
|
+
if uuid.present? || session_id.present?
|
43
|
+
uuid ||= '-'
|
44
|
+
session_id ||= '-'
|
45
|
+
logger.formatter = proc do |severity, time, progname, msg|
|
46
|
+
"[%s#%d] %5s -- %s: [#{uuid}] [#{session_id}] %s\n" % [format_datetime(time), $$, severity, progname, msg2str(msg)]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# @param [Hash] hash
|
52
|
+
def skip_sensitive_data(hash)
|
53
|
+
if hash.is_a? Hash
|
54
|
+
redacted = hash.clone
|
55
|
+
redacted.update(redacted) { |key, v1| (PROTECTED_KEYS.include? key) ? '[REDACTED]' : v1 }
|
56
|
+
else
|
57
|
+
hash
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
def format_datetime(time)
|
63
|
+
time.strftime('%Y-%m-%dT%H:%M:%S.') << '%06d ' % time.usec
|
64
|
+
end
|
65
|
+
|
66
|
+
def msg2str(msg)
|
67
|
+
case msg
|
68
|
+
when ::String
|
69
|
+
msg
|
70
|
+
when ::Exception
|
71
|
+
"#{ msg.message } (#{ msg.class })\n" << (msg.backtrace || []).join("\n")
|
72
|
+
else
|
73
|
+
msg.inspect
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class Object
|
2
|
+
# An object is blank if it's false, empty, or a whitespace string.
|
3
|
+
# For example, "", " ", +nil+, [], and {} are all blank.
|
4
|
+
#
|
5
|
+
# This simplifies:
|
6
|
+
#
|
7
|
+
# if address.nil? || address.empty?
|
8
|
+
#
|
9
|
+
# ...to:
|
10
|
+
#
|
11
|
+
# if address.blank?
|
12
|
+
def blank?
|
13
|
+
respond_to?(:empty?) ? empty? : !self
|
14
|
+
end
|
15
|
+
|
16
|
+
# An object is present if it's not <tt>blank?</tt>.
|
17
|
+
def present?
|
18
|
+
!blank?
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns object if it's <tt>present?</tt> otherwise returns +nil+.
|
22
|
+
# <tt>object.presence</tt> is equivalent to <tt>object.present? ? object : nil</tt>.
|
23
|
+
#
|
24
|
+
# This is handy for any representation of objects where blank is the same
|
25
|
+
# as not present at all. For example, this simplifies a common check for
|
26
|
+
# HTTP POST/query parameters:
|
27
|
+
#
|
28
|
+
# state = params[:state] if params[:state].present?
|
29
|
+
# country = params[:country] if params[:country].present?
|
30
|
+
# region = state || country || 'US'
|
31
|
+
#
|
32
|
+
# ...becomes:
|
33
|
+
#
|
34
|
+
# region = params[:state].presence || params[:country].presence || 'US'
|
35
|
+
def presence
|
36
|
+
self if present?
|
37
|
+
end
|
38
|
+
|
39
|
+
def trim
|
40
|
+
respond_to?(:strip) ? self.strip : self
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Hash
|
45
|
+
def validate_required_strings!
|
46
|
+
self.each do |key, value|
|
47
|
+
raise MissingArgumentsError.new "Missing argument: #{key}." if value.blank?
|
48
|
+
raise InvalidArgumentsError.new "Invalid #{key} specified: #{value.inspect} must be a string or symbol." unless value.is_a?(String) || value.is_a?(Symbol)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/finapps.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'finapps/version' unless defined?(FinApps::VERSION)
|
2
|
+
require 'logger' unless defined?(::Logger)
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
require 'faraday'
|
6
|
+
require 'faraday_middleware'
|
7
|
+
require 'typhoeus'
|
8
|
+
require 'typhoeus/adapters/faraday'
|
9
|
+
|
10
|
+
require 'finapps/rest/defaults'
|
11
|
+
require 'finapps/rest/errors'
|
12
|
+
require 'finapps/utils/logging'
|
13
|
+
require 'finapps/utils/utils'
|
14
|
+
|
15
|
+
require 'finapps/rest/resource'
|
16
|
+
require 'finapps/rest/resources'
|
17
|
+
require 'finapps/rest/users'
|
18
|
+
require 'finapps/rest/institutions'
|
19
|
+
|
20
|
+
require 'finapps/middleware/api_token'
|
21
|
+
require 'finapps/middleware/raise_http_exceptions'
|
22
|
+
require 'finapps/middleware/response_logger'
|
23
|
+
|
24
|
+
require 'finapps/rest/connection'
|
25
|
+
require 'finapps/rest/client'
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'finapps'
|
3
|
+
|
4
|
+
module FinApps
|
5
|
+
|
6
|
+
describe FinApps::REST::Client do
|
7
|
+
|
8
|
+
before do
|
9
|
+
@client = FinApps::REST::Client.new :company_identifier, :company_token
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#new' do
|
13
|
+
context 'when company credentials are NOT provided' do
|
14
|
+
it 'should raise a MissingArgumentsError exception' do
|
15
|
+
expect { FinApps::REST::Client.new nil, nil }.to raise_error(FinApps::REST::MissingArgumentsError)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when company credentials are of invalid type' do
|
20
|
+
it 'should raise an InvalidArgumentsError exception' do
|
21
|
+
expect{FinApps::REST::Client.new 1, 2}.to raise_error(FinApps::REST::InvalidArgumentsError)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when company credentials are provided' do
|
26
|
+
it 'returns a client object' do
|
27
|
+
expect(@client).to be_an_instance_of(FinApps::REST::Client)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#get' do
|
33
|
+
it 'responds to get' do
|
34
|
+
expect(@client).to respond_to(:get)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#post' do
|
39
|
+
it 'responds to post' do
|
40
|
+
expect(@client).to respond_to(:post)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '.users' do
|
45
|
+
it 'returns a Users object' do
|
46
|
+
expect(@client.users).to be_an_instance_of(FinApps::REST::Users)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#connection' do
|
51
|
+
it 'looks like Faraday connection' do
|
52
|
+
expect(@client.send(:connection)).to respond_to(:run_request)
|
53
|
+
end
|
54
|
+
it 'memoizes the connection' do
|
55
|
+
c1, c2 = @client.send(:connection), @client.send(:connection)
|
56
|
+
expect(c1.object_id).to eq(c2.object_id)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'finapps'
|
2
|
+
|
3
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
4
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
5
|
+
# The generated `.rspec` file contains `--require spec_helper` which will cause this
|
6
|
+
# file to always be loaded, without a need to explicitly require it in any files.
|
7
|
+
#
|
8
|
+
# Given that it is always loaded, you are encouraged to keep this file as
|
9
|
+
# light-weight as possible. Requiring heavyweight dependencies from this file
|
10
|
+
# will add to the boot time of your test suite on EVERY test run, even for an
|
11
|
+
# individual file that may not need all of that loaded. Instead, make a
|
12
|
+
# separate helper file that requires this one and then use it only in the specs
|
13
|
+
# that actually need it.
|
14
|
+
#
|
15
|
+
# The `.rspec` file also contains a few flags that are not defaults but that
|
16
|
+
# users commonly want.
|
17
|
+
#
|
18
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
19
|
+
RSpec.configure do |config|
|
20
|
+
|
21
|
+
# These two settings work together to allow you to limit a spec run
|
22
|
+
# to individual examples or groups you care about by tagging them with
|
23
|
+
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
24
|
+
# get run.
|
25
|
+
config.filter_run :focus
|
26
|
+
config.run_all_when_everything_filtered = true
|
27
|
+
|
28
|
+
# Many RSpec users commonly either run the entire suite or an individual
|
29
|
+
# file, and it's useful to allow more verbose output when running an
|
30
|
+
# individual spec file.
|
31
|
+
if config.files_to_run.one?
|
32
|
+
# Use the documentation formatter for detailed output,
|
33
|
+
# unless a formatter has already been configured
|
34
|
+
# (e.g. via a command-line flag).
|
35
|
+
config.default_formatter = 'doc'
|
36
|
+
end
|
37
|
+
|
38
|
+
# Run specs in random order to surface order dependencies. If you find an
|
39
|
+
# order dependency and want to debug it, you can fix the order by providing
|
40
|
+
# the seed, which is printed after each run.
|
41
|
+
# --seed 1234
|
42
|
+
config.order = :random
|
43
|
+
|
44
|
+
# The settings below are suggested to provide a good initial experience
|
45
|
+
# with RSpec, but feel free to customize to your heart's content.
|
46
|
+
=begin
|
47
|
+
|
48
|
+
# Print the 10 slowest examples and example groups at the
|
49
|
+
# end of the spec run, to help surface which specs are running
|
50
|
+
# particularly slow.
|
51
|
+
config.profile_examples = 10
|
52
|
+
|
53
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
54
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
55
|
+
# test failures related to randomization by passing the same `--seed` value
|
56
|
+
# as the one that triggered the failure.
|
57
|
+
Kernel.srand config.seed
|
58
|
+
|
59
|
+
# rspec-expectations config goes here. You can use an alternate
|
60
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
61
|
+
# assertions if you prefer.
|
62
|
+
config.expect_with :rspec do |expectations|
|
63
|
+
# Enable only the newer, non-monkey-patching expect syntax.
|
64
|
+
# For more details, see:
|
65
|
+
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
|
66
|
+
expectations.syntax = :expect
|
67
|
+
end
|
68
|
+
|
69
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
70
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
71
|
+
config.mock_with :rspec do |mocks|
|
72
|
+
# Enable only the newer, non-monkey-patching expect syntax.
|
73
|
+
# For more details, see:
|
74
|
+
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
75
|
+
mocks.syntax = :expect
|
76
|
+
|
77
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
78
|
+
# a real object. This is generally recommended.
|
79
|
+
mocks.verify_partial_doubles = true
|
80
|
+
end
|
81
|
+
=end
|
82
|
+
|
83
|
+
|
84
|
+
end
|