nearmiss-ruby 1.0.0
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/AUTHORS.md +7 -0
- data/CHANGELOG.md +16 -0
- data/Gemfile +9 -0
- data/LICENSE +20 -0
- data/README.md +188 -0
- data/Rakefile +10 -0
- data/lib/nearmiss-ruby/arguments.rb +14 -0
- data/lib/nearmiss-ruby/authentication.rb +60 -0
- data/lib/nearmiss-ruby/client/account.rb +14 -0
- data/lib/nearmiss-ruby/client/bookmarks.rb +39 -0
- data/lib/nearmiss-ruby/client/categories.rb +72 -0
- data/lib/nearmiss-ruby/client/incidents.rb +155 -0
- data/lib/nearmiss-ruby/client/notifications.rb +31 -0
- data/lib/nearmiss-ruby/client/projects.rb +76 -0
- data/lib/nearmiss-ruby/client/rate_limit.rb +52 -0
- data/lib/nearmiss-ruby/client/users.rb +81 -0
- data/lib/nearmiss-ruby/client.rb +307 -0
- data/lib/nearmiss-ruby/configurable.rb +53 -0
- data/lib/nearmiss-ruby/default.rb +137 -0
- data/lib/nearmiss-ruby/error.rb +186 -0
- data/lib/nearmiss-ruby/raise_error.rb +19 -0
- data/lib/nearmiss-ruby/rate_limit.rb +33 -0
- data/lib/nearmiss-ruby/response.rb +7 -0
- data/lib/nearmiss-ruby/util.rb +32 -0
- data/lib/nearmiss-ruby/version.rb +3 -0
- data/lib/nearmiss-ruby.rb +46 -0
- data/nearmiss-ruby.gemspec +28 -0
- metadata +115 -0
@@ -0,0 +1,186 @@
|
|
1
|
+
module Nearmiss
|
2
|
+
# Custom error class for rescuing from all GitHub errors
|
3
|
+
class Error < StandardError
|
4
|
+
|
5
|
+
# Returns the appropriate Nearmiss::Error sublcass based
|
6
|
+
# on status and response message
|
7
|
+
#
|
8
|
+
# @param [Hash] response HTTP response
|
9
|
+
# @return [Nearmiss::Error]
|
10
|
+
def self.from_response(response)
|
11
|
+
status = response[:status].to_i
|
12
|
+
body = response[:body].to_s
|
13
|
+
headers = response[:response_headers]
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
if klass = case status
|
18
|
+
when 400 then Nearmiss::BadRequest
|
19
|
+
when 401 then Nearmiss::Unauthorized
|
20
|
+
when 403 then Nearmiss::Forbidden
|
21
|
+
when 404 then Nearmiss::NotFound
|
22
|
+
when 405 then Nearmiss::MethodNotAllowed
|
23
|
+
when 406 then Nearmiss::NotAcceptable
|
24
|
+
when 409 then Nearmiss::Conflict
|
25
|
+
when 415 then Nearmiss::UnsupportedMediaType
|
26
|
+
when 422 then Nearmiss::UnprocessableEntity
|
27
|
+
when 400..499 then Nearmiss::ClientError
|
28
|
+
when 500 then Nearmiss::InternalServerError
|
29
|
+
when 501 then Nearmiss::NotImplemented
|
30
|
+
when 502 then Nearmiss::BadGateway
|
31
|
+
when 503 then Nearmiss::ServiceUnavailable
|
32
|
+
when 500..599 then Nearmiss::ServerError
|
33
|
+
end
|
34
|
+
klass.new(response)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(response=nil)
|
39
|
+
@response = response
|
40
|
+
super(build_error_message)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Array of validation errors
|
44
|
+
# @return [Array<Hash>] Error info
|
45
|
+
def errors
|
46
|
+
if data && data.is_a?(Hash)
|
47
|
+
data[:errors] || []
|
48
|
+
else
|
49
|
+
[]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# private
|
54
|
+
|
55
|
+
def data
|
56
|
+
@data ||=
|
57
|
+
if (body = @response[:body]) && !body.empty?
|
58
|
+
if body.is_a?(String) &&
|
59
|
+
@response[:response_headers] &&
|
60
|
+
@response[:response_headers][:content_type] =~ /json/
|
61
|
+
|
62
|
+
Sawyer::Agent.serializer.decode(body)
|
63
|
+
else
|
64
|
+
body
|
65
|
+
end
|
66
|
+
else
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def response_message
|
72
|
+
case data
|
73
|
+
when Hash
|
74
|
+
data[:message]
|
75
|
+
when String
|
76
|
+
data
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def response_error
|
81
|
+
"Error: #{data[:error]}" if data.is_a?(Hash) && data[:error]
|
82
|
+
end
|
83
|
+
|
84
|
+
def response_error_summary
|
85
|
+
return nil unless data.is_a?(Hash) && !Array(data[:errors]).empty?
|
86
|
+
|
87
|
+
summary = "\nError summary:\n"
|
88
|
+
# summary << data[:errors].map do |hash|
|
89
|
+
# hash.map { |k,v| " #{k}: #{v}" }
|
90
|
+
# end.join("\n")
|
91
|
+
summary << data[:errors].join("\n")
|
92
|
+
summary
|
93
|
+
end
|
94
|
+
|
95
|
+
def build_error_message
|
96
|
+
return nil if @response.nil?
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
message = "#{@response[:method].to_s.upcase} "
|
101
|
+
message << redact_url(@response[:url].to_s) + ": "
|
102
|
+
message << "#{@response[:status]} - "
|
103
|
+
message << "#{response_message}" unless response_message.nil?
|
104
|
+
message << "#{response_error}" unless response_error.nil?
|
105
|
+
message << "#{response_error_summary}" unless response_error_summary.nil?
|
106
|
+
# message << MultiJson.dump(@response)
|
107
|
+
message
|
108
|
+
end
|
109
|
+
|
110
|
+
def redact_url(url_string)
|
111
|
+
%w[client_secret access_token].each do |token|
|
112
|
+
url_string.gsub!(/#{token}=\S+/, "#{token}=(redacted)") if url_string.include? token
|
113
|
+
end
|
114
|
+
url_string
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
# Raised on errors in the 400-499 range
|
120
|
+
class ClientError < Error; end
|
121
|
+
|
122
|
+
# Raised when Nearmiss-Field returns a 400 HTTP status code
|
123
|
+
class BadRequest < ClientError; end
|
124
|
+
|
125
|
+
# Raised when Nearmiss-Field returns a 401 HTTP status code
|
126
|
+
class Unauthorized < ClientError; end
|
127
|
+
# Raised when Nearmiss-Field returns a 403 HTTP status code
|
128
|
+
class Forbidden < ClientError; end
|
129
|
+
|
130
|
+
# Raised when Nearmiss-Field returns a 403 HTTP status code
|
131
|
+
# and body matches 'rate limit exceeded'
|
132
|
+
class TooManyRequests < Forbidden; end
|
133
|
+
|
134
|
+
# Raised when Nearmiss-Field returns a 403 HTTP status code
|
135
|
+
# and body matches 'login attempts exceeded'
|
136
|
+
class TooManyLoginAttempts < Forbidden; end
|
137
|
+
|
138
|
+
# Raised when Nearmiss-Field returns a 404 HTTP status code
|
139
|
+
class NotFound < ClientError; end
|
140
|
+
|
141
|
+
# Raised when Nearmiss-Field returns a 405 HTTP status code
|
142
|
+
class MethodNotAllowed < ClientError; end
|
143
|
+
|
144
|
+
# Raised when Nearmiss-Field returns a 406 HTTP status code
|
145
|
+
class NotAcceptable < ClientError; end
|
146
|
+
|
147
|
+
# Raised when Nearmiss-Field returns a 409 HTTP status code
|
148
|
+
class Conflict < ClientError; end
|
149
|
+
|
150
|
+
# Raised when Nearmiss-Field returns a 414 HTTP status code
|
151
|
+
class UnsupportedMediaType < ClientError; end
|
152
|
+
|
153
|
+
# Raised when Nearmiss-Field returns a 422 HTTP status code
|
154
|
+
class UnprocessableEntity < ClientError; end
|
155
|
+
|
156
|
+
# Raised on errors in the 500-599 range
|
157
|
+
class ServerError < Error; end
|
158
|
+
|
159
|
+
# Raised when Nearmiss-Field returns a 500 HTTP status code
|
160
|
+
class InternalServerError < ServerError; end
|
161
|
+
|
162
|
+
# Raised when Nearmiss-Field returns a 501 HTTP status code
|
163
|
+
class NotImplemented < ServerError; end
|
164
|
+
|
165
|
+
# Raised when Nearmiss-Field returns a 502 HTTP status code
|
166
|
+
class BadGateway < ServerError; end
|
167
|
+
|
168
|
+
# Raised when Nearmiss-Field returns a 503 HTTP status code
|
169
|
+
class ServiceUnavailable < ServerError; end
|
170
|
+
|
171
|
+
# Raised when client fails to provide valid Content-Type
|
172
|
+
class MissingContentType < ArgumentError; end
|
173
|
+
|
174
|
+
# Raised when a method requires an application client_id
|
175
|
+
# and secret but none is provided
|
176
|
+
class ApplicationCredentialsRequired < StandardError; end
|
177
|
+
|
178
|
+
class MissingParams < Error
|
179
|
+
def initialize(msg)
|
180
|
+
|
181
|
+
msg
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
module Nearmiss
|
3
|
+
# Faraday response middleware
|
4
|
+
module Response
|
5
|
+
|
6
|
+
# This class raises an Nearmiss-flavored exception based
|
7
|
+
# HTTP status codes returned by the API
|
8
|
+
class RaiseError < Faraday::Response::Middleware
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def on_complete(response)
|
13
|
+
if error = Nearmiss::Error.from_response(response)
|
14
|
+
raise error
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Nearmiss
|
2
|
+
|
3
|
+
# Class for API Rate Limit info
|
4
|
+
#
|
5
|
+
# @!attribute [w] limit
|
6
|
+
# @return [Fixnum] Max tries per rate limit period
|
7
|
+
# @!attribute [w] remaining
|
8
|
+
# @return [Fixnum] Remaining tries per rate limit period
|
9
|
+
# @!attribute [w] resets_at
|
10
|
+
# @return [Time] Indicates when rate limit resets
|
11
|
+
# @!attribute [w] resets_in
|
12
|
+
# @return [Fixnum] Number of seconds when rate limit resets
|
13
|
+
#
|
14
|
+
# @see https://developer.github.com/v3/#rate-limiting
|
15
|
+
class RateLimit < Struct.new(:limit, :remaining, :resets_at, :resets_in)
|
16
|
+
|
17
|
+
# Get rate limit info from HTTP response
|
18
|
+
#
|
19
|
+
# @param response [#headers] HTTP response
|
20
|
+
# @return [RateLimit]
|
21
|
+
def self.from_response(response)
|
22
|
+
info = new
|
23
|
+
if response && !response.headers.nil?
|
24
|
+
info.limit = (response.headers['X-RateLimit-Limit'] || 1).to_i
|
25
|
+
info.remaining = (response.headers['X-RateLimit-Remaining'] || 1).to_i
|
26
|
+
info.resets_at = Time.at((response.headers['X-RateLimit-Reset'] || Time.now).to_i)
|
27
|
+
info.resets_in = [(info.resets_at - Time.now).to_i, 0].max
|
28
|
+
end
|
29
|
+
|
30
|
+
info
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Nearmiss
|
2
|
+
module Util
|
3
|
+
def url_encode(hash)
|
4
|
+
hash.to_a.map {|p| p.map {|e| CGI.escape get_string(e)}.join '='}.join '&'
|
5
|
+
end
|
6
|
+
|
7
|
+
def get_string(obj)
|
8
|
+
if obj.respond_to?(:strftime)
|
9
|
+
obj.strftime('%Y-%m-%d')
|
10
|
+
else
|
11
|
+
obj.to_s
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Validate if argument is a UUID
|
16
|
+
#
|
17
|
+
# @param uuid [String] the string to test against
|
18
|
+
# @return [Boolean]
|
19
|
+
# @example
|
20
|
+
# Nearmiss.uuid?("31817811-dce4-48c4-aa5f-f49603c5abee") => true
|
21
|
+
# Nearmiss.uuid?("test@gmail.com") => false
|
22
|
+
#
|
23
|
+
def uuid?(uuid)
|
24
|
+
return true if uuid =~ /\A[\da-f]{32}\z/i
|
25
|
+
return true if
|
26
|
+
uuid =~ /\A(urn:uuid:)?[\da-f]{8}-([\da-f]{4}-){3}[\da-f]{12}\z/i
|
27
|
+
return false
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "set"
|
2
|
+
require "faraday"
|
3
|
+
require "sawyer"
|
4
|
+
|
5
|
+
require "nearmiss-ruby/response"
|
6
|
+
require "nearmiss-ruby/error"
|
7
|
+
require "nearmiss-ruby/raise_error"
|
8
|
+
require "nearmiss-ruby/version"
|
9
|
+
|
10
|
+
require "nearmiss-ruby/configurable"
|
11
|
+
require "nearmiss-ruby/response"
|
12
|
+
require "nearmiss-ruby/client"
|
13
|
+
require "nearmiss-ruby/default"
|
14
|
+
require "nearmiss-ruby/util"
|
15
|
+
|
16
|
+
module Nearmiss
|
17
|
+
|
18
|
+
class << self
|
19
|
+
|
20
|
+
include Nearmiss::Configurable
|
21
|
+
include Nearmiss::Util
|
22
|
+
|
23
|
+
# API client based on configured options {Configurable}
|
24
|
+
#
|
25
|
+
# @return [Nearmiss::Client] API wrapper
|
26
|
+
def client
|
27
|
+
@client = Nearmiss::Client.new(options) unless defined?(@client) && @client.same_options?(options)
|
28
|
+
@client
|
29
|
+
end
|
30
|
+
|
31
|
+
# @private
|
32
|
+
def respond_to_missing?(method_name, include_private=false)
|
33
|
+
client.respond_to?(method_name, include_private)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def method_missing(method_name, *args, &block)
|
39
|
+
return super unless client.respond_to?(method_name)
|
40
|
+
client.send(method_name, *args, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
Nearmiss.setup
|
@@ -0,0 +1,28 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{nearmiss-ruby}
|
3
|
+
s.version = "1.0.0"
|
4
|
+
s.platform = Gem::Platform::RUBY
|
5
|
+
s.license = 'MIT'
|
6
|
+
|
7
|
+
s.authors = ["Markus Klooth"]
|
8
|
+
s.date = Time.now.strftime "%Y-%m-%d"
|
9
|
+
s.description = %q{A wrapper around the nearmissapp.com API.}
|
10
|
+
s.email = %q{support@nearmissapp.com}
|
11
|
+
s.extra_rdoc_files = ["README.md"]
|
12
|
+
s.files = `git ls-files -z`.split("\x0")
|
13
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
14
|
+
s.homepage = %q{https://github.com/nearmiss/nearmiss-ruby}
|
15
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.rubyforge_project = %q{nearmiss-ruby}
|
18
|
+
s.rubygems_version = %q{1.0.0}
|
19
|
+
s.summary = %q{A wrapper around the nearmiss.com API.}
|
20
|
+
s.test_files = Dir.glob("spec/**/*")
|
21
|
+
|
22
|
+
s.required_ruby_version = '>= 1.9.3'
|
23
|
+
|
24
|
+
s.add_dependency("sawyer", ">= 0.5.5")
|
25
|
+
s.add_dependency("multi_json", '>= 1.3.0')
|
26
|
+
|
27
|
+
s.add_development_dependency 'bundler', '~> 1.0'
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nearmiss-ruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Markus Klooth
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-01-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: sawyer
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.5.5
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.5.5
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: multi_json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.3.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.3.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.0'
|
55
|
+
description: A wrapper around the nearmissapp.com API.
|
56
|
+
email: support@nearmissapp.com
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files:
|
60
|
+
- README.md
|
61
|
+
files:
|
62
|
+
- AUTHORS.md
|
63
|
+
- CHANGELOG.md
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- lib/nearmiss-ruby.rb
|
69
|
+
- lib/nearmiss-ruby/arguments.rb
|
70
|
+
- lib/nearmiss-ruby/authentication.rb
|
71
|
+
- lib/nearmiss-ruby/client.rb
|
72
|
+
- lib/nearmiss-ruby/client/account.rb
|
73
|
+
- lib/nearmiss-ruby/client/bookmarks.rb
|
74
|
+
- lib/nearmiss-ruby/client/categories.rb
|
75
|
+
- lib/nearmiss-ruby/client/incidents.rb
|
76
|
+
- lib/nearmiss-ruby/client/notifications.rb
|
77
|
+
- lib/nearmiss-ruby/client/projects.rb
|
78
|
+
- lib/nearmiss-ruby/client/rate_limit.rb
|
79
|
+
- lib/nearmiss-ruby/client/users.rb
|
80
|
+
- lib/nearmiss-ruby/configurable.rb
|
81
|
+
- lib/nearmiss-ruby/default.rb
|
82
|
+
- lib/nearmiss-ruby/error.rb
|
83
|
+
- lib/nearmiss-ruby/raise_error.rb
|
84
|
+
- lib/nearmiss-ruby/rate_limit.rb
|
85
|
+
- lib/nearmiss-ruby/response.rb
|
86
|
+
- lib/nearmiss-ruby/util.rb
|
87
|
+
- lib/nearmiss-ruby/version.rb
|
88
|
+
- nearmiss-ruby.gemspec
|
89
|
+
homepage: https://github.com/nearmiss/nearmiss-ruby
|
90
|
+
licenses:
|
91
|
+
- MIT
|
92
|
+
metadata: {}
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options:
|
95
|
+
- "--charset=UTF-8"
|
96
|
+
require_paths:
|
97
|
+
- lib
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 1.9.3
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
requirements: []
|
109
|
+
rubyforge_project: nearmiss-ruby
|
110
|
+
rubygems_version: 2.2.2
|
111
|
+
signing_key:
|
112
|
+
specification_version: 4
|
113
|
+
summary: A wrapper around the nearmiss.com API.
|
114
|
+
test_files: []
|
115
|
+
has_rdoc:
|