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.
@@ -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,7 @@
1
+ module Nearmiss
2
+
3
+ module Response
4
+
5
+ end
6
+
7
+ 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,3 @@
1
+ module Nearmiss
2
+ VERSION = "0.0.1"
3
+ 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: