namira 0.2.1 → 1.0.0.rc1
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 +4 -4
- data/.circleci/config.yml +37 -0
- data/.rspec +1 -1
- data/.rubocop.yml +4 -10
- data/CHANGELOG.md +3 -0
- data/README.md +11 -0
- data/Rakefile +9 -3
- data/bin/console +3 -3
- data/lib/namira/auth/base.rb +15 -0
- data/lib/namira/auth/http_basic.rb +9 -0
- data/lib/namira/backend.rb +109 -38
- data/lib/namira/config.rb +50 -10
- data/lib/namira/errors/base_error.rb +10 -0
- data/lib/namira/errors/http_error.rb +18 -2
- data/lib/namira/errors/invalid_uri_error.rb +11 -0
- data/lib/namira/errors/redirect_error.rb +23 -1
- data/lib/namira/errors/timeout_error.rb +11 -0
- data/lib/namira/errors.rb +10 -3
- data/lib/namira/query_builder.rb +16 -1
- data/lib/namira/request.rb +30 -5
- data/lib/namira/response.rb +20 -4
- data/lib/namira/version.rb +3 -1
- data/lib/namira.rb +4 -2
- data/namira.gemspec +9 -14
- metadata +70 -28
- data/lib/namira/errors/base.rb +0 -6
- data/lib/namira/errors/timeout.rb +0 -6
- data/lib/namira/errors/too_many_redirects.rb +0 -6
- data/lib/namira/extensions/hash_key_path.rb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f8a61a21ca4adf902c8b0b7a19e858264003c439
|
4
|
+
data.tar.gz: 2f2fcb31c8680d3435ff527c437cefcbe8c8ddf4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71a2b284cf3121bf7b92ed4ac1ec4620cff69190823935cdf1b869b1236f1de58fdb43f59bf46138fd67f20ecede24626d0f953c5c710a0b583f9559f29d346c
|
7
|
+
data.tar.gz: 5c84411bc338cd23d6d715cab691c3dc48ee668234b47bdd3386b18ee31e90ee71453b27ed2b8e96f04afcfd7d40b459db5accc3daf17dda6253e07ff51250d5
|
@@ -0,0 +1,37 @@
|
|
1
|
+
version: 2
|
2
|
+
jobs:
|
3
|
+
build:
|
4
|
+
environment:
|
5
|
+
CC_TEST_REPORTER_ID: 1c8715d8f4fb6cb280a974b7a537ea5e10dd93e92e1267db5e9dadb3b32cf178
|
6
|
+
docker:
|
7
|
+
- image: circleci/ruby:2.4.2
|
8
|
+
working_directory: ~/repo
|
9
|
+
steps:
|
10
|
+
- checkout
|
11
|
+
- run:
|
12
|
+
name: Setup Code Climate test-reporter
|
13
|
+
command: |
|
14
|
+
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
15
|
+
chmod +x ./cc-test-reporter
|
16
|
+
- restore_cache:
|
17
|
+
keys:
|
18
|
+
- v1-gems-{{ checksum "namira.gemspec" }}
|
19
|
+
- v1-gems-
|
20
|
+
- run:
|
21
|
+
name: install gems
|
22
|
+
command: |
|
23
|
+
bundle install --jobs=4 --retry=3 --path vendor/bundle
|
24
|
+
- save_cache:
|
25
|
+
key: v1-gems-{{ checksum "namira.gemspec" }}
|
26
|
+
paths:
|
27
|
+
- ./vendor/bundle
|
28
|
+
- run:
|
29
|
+
name: Run Specs
|
30
|
+
command: bundle exec rspec spec/**/*.rb
|
31
|
+
- run:
|
32
|
+
name: Report Coverage
|
33
|
+
command: |
|
34
|
+
./cc-test-reporter format-coverage -t simplecov $CIRCLE_ARTIFACTS/coverage/.resultset.json
|
35
|
+
./cc-test-reporter upload-coverage
|
36
|
+
- store_artifacts:
|
37
|
+
path: coverage/coverage.json
|
data/.rspec
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
--format
|
1
|
+
--format progress
|
2
2
|
--color
|
data/.rubocop.yml
CHANGED
@@ -2,7 +2,7 @@ AllCops:
|
|
2
2
|
TargetRubyVersion: 2.2
|
3
3
|
Exclude:
|
4
4
|
- Rakefile
|
5
|
-
-
|
5
|
+
- spec/**/*
|
6
6
|
|
7
7
|
Metrics/AbcSize:
|
8
8
|
Max: 30
|
@@ -25,24 +25,18 @@ DotPosition:
|
|
25
25
|
StringLiterals:
|
26
26
|
EnforcedStyle: single_quotes
|
27
27
|
|
28
|
-
|
28
|
+
Layout/AlignParameters:
|
29
29
|
EnforcedStyle: with_fixed_indentation
|
30
30
|
|
31
|
-
|
31
|
+
Layout/MultilineOperationIndentation:
|
32
32
|
EnforcedStyle: indented
|
33
33
|
|
34
|
-
|
34
|
+
Layout/MultilineMethodCallIndentation:
|
35
35
|
EnforcedStyle: indented
|
36
36
|
|
37
|
-
Style/ExtraSpacing:
|
38
|
-
Enabled: false
|
39
|
-
|
40
37
|
Style/AndOr:
|
41
38
|
EnforcedStyle: conditionals
|
42
39
|
|
43
|
-
Style/Documentation:
|
44
|
-
Enabled: false
|
45
|
-
|
46
40
|
Style/ClassAndModuleChildren:
|
47
41
|
Enabled: false
|
48
42
|
|
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Namira
|
2
2
|
|
3
|
+
[](https://badge.fury.io/rb/namira)
|
4
|
+
[](https://circleci.com/gh/skylarsch/namira/tree/master)
|
5
|
+
[](https://codeclimate.com/github/skylarsch/namira/maintainability)
|
6
|
+
[](https://codeclimate.com/github/skylarsch/namira/test_coverage)
|
7
|
+
|
8
|
+
A Ruby HTTP client.
|
9
|
+
|
3
10
|
## Installation
|
4
11
|
|
5
12
|
Add this line to your application's Gemfile:
|
@@ -16,6 +23,10 @@ Or install it yourself as:
|
|
16
23
|
|
17
24
|
$ gem install namira
|
18
25
|
|
26
|
+
## Documentation
|
27
|
+
|
28
|
+
Run `bundle exec yard`
|
29
|
+
|
19
30
|
## Usage
|
20
31
|
|
21
32
|
### GET
|
data/Rakefile
CHANGED
@@ -1,6 +1,12 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'yard'
|
3
4
|
|
4
5
|
RSpec::Core::RakeTask.new(:spec)
|
5
6
|
|
6
|
-
task :
|
7
|
+
task default: :spec
|
8
|
+
|
9
|
+
YARD::Rake::YardocTask.new do |t|
|
10
|
+
t.files = ['lib/**/*.rb'] # optional
|
11
|
+
t.stats_options = ['--list-undoc'] # optional
|
12
|
+
end
|
data/bin/console
CHANGED
data/lib/namira/auth/base.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
module Namira
|
2
|
+
##
|
3
|
+
# Authentication
|
2
4
|
module Auth
|
5
|
+
##
|
6
|
+
# The base authentication class
|
3
7
|
class Base
|
4
8
|
attr_accessor :sign_redirects
|
5
9
|
|
@@ -11,11 +15,22 @@ module Namira
|
|
11
15
|
end
|
12
16
|
end
|
13
17
|
|
18
|
+
##
|
19
|
+
# @private
|
20
|
+
#
|
21
|
+
# Signs a request.
|
22
|
+
#
|
23
|
+
# @param backend [HTTP] The request being signed
|
24
|
+
# @param redirect_count [Integer] The number of redirects this request has encountered
|
14
25
|
def sign_request(backend, redirect_count)
|
15
26
|
return if redirect_count > 0 && !sign_redirects?
|
16
27
|
sign(backend)
|
17
28
|
end
|
18
29
|
|
30
|
+
##
|
31
|
+
# Perform the signing of the request
|
32
|
+
#
|
33
|
+
# @param backend [HTTP] The instance of the backend request to sign.
|
19
34
|
def sign(_backend)
|
20
35
|
raise NotImplementedError, 'Auth should override the `sign` method'
|
21
36
|
end
|
@@ -1,13 +1,22 @@
|
|
1
1
|
module Namira
|
2
2
|
module Auth
|
3
|
+
##
|
4
|
+
# Signs a HTTP request with HTTP basic authentication
|
3
5
|
class HTTPBasic < Base
|
4
6
|
attr_reader :user, :pass
|
5
7
|
|
8
|
+
##
|
9
|
+
# Create a new instance
|
10
|
+
#
|
11
|
+
# @param user [String] The username
|
12
|
+
# @param pass [String] The password
|
6
13
|
def initialize(user:, pass:)
|
7
14
|
@user = user
|
8
15
|
@pass = pass
|
9
16
|
end
|
10
17
|
|
18
|
+
##
|
19
|
+
# Signs the request
|
11
20
|
def sign(request)
|
12
21
|
request.basic_auth(user: user, pass: pass)
|
13
22
|
end
|
data/lib/namira/backend.rb
CHANGED
@@ -1,66 +1,137 @@
|
|
1
1
|
module Namira
|
2
|
+
##
|
3
|
+
# The backend is responsible for sending the requests.
|
4
|
+
#
|
5
|
+
# Namira uses HTTP Gem as its default backend. You can create your own backend and override `.send_request` to
|
6
|
+
# use a different network stack.
|
7
|
+
#
|
8
|
+
# Namira.config do |c|
|
9
|
+
# c.backend = CustomBackend
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# A fully compatable backend should handle redirects, respecting the max_redirect parameter as well as
|
13
|
+
# throwing a Errors::HTTPError for anything but a redirect & 2xx status code.
|
2
14
|
class Backend
|
3
|
-
|
15
|
+
##
|
4
16
|
# This allows anyone to substitute in their own networking stack.
|
5
17
|
#
|
6
18
|
# Any class that implements this method and resturns a `Namira::Response` object can be a fully qualified backend.
|
7
19
|
#
|
8
|
-
# The
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# timeout: The number of seconds before a timeout should occure
|
15
|
-
# auth: The Namira::Auth::Base subclass instance or nil to sign the request with
|
16
|
-
#
|
17
|
-
# This class is 100% capable of fufilling all Namira's needs.
|
18
|
-
# But this is an option if you really need to provide a custom networking backend
|
20
|
+
# @param uri [String] The URI to fetch
|
21
|
+
# @param method [Symbol] The HTTP method to use, expressed as a Symbol i.e. `:get`
|
22
|
+
# @param headers [Hash] The full HTTP headers to send from the request expressed as a Hash
|
23
|
+
# @param max_redirect [Integer] The maximum number of redirects to follow. Passed from the Request
|
24
|
+
# @param timeout [Integer] The number of seconds before a timeout should occure
|
25
|
+
# @param auth [Namira::Auth::Base] The `Namira::Auth::Base` subclass instance or nil to sign the request with
|
19
26
|
#
|
27
|
+
# @return [Namira::Response] The HTTP response
|
20
28
|
def self.send_request(uri:, method:, headers:, max_redirect:, timeout:, body:, auth:)
|
21
|
-
Backend.new
|
29
|
+
Backend.new(
|
30
|
+
uri: uri,
|
31
|
+
method: method,
|
32
|
+
headers: headers,
|
33
|
+
max_redirect: max_redirect,
|
34
|
+
timeout: timeout,
|
35
|
+
body: body,
|
36
|
+
auth: auth
|
37
|
+
).execute
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# The default max redirects to consider the request a "no follow"
|
42
|
+
NO_FOLLOW_REDIRECT_COUNT = -1
|
43
|
+
|
44
|
+
##
|
45
|
+
# @private
|
46
|
+
def initialize(opts = {})
|
47
|
+
opts.each do |key, value|
|
48
|
+
instance_variable_set("@#{key}", value)
|
49
|
+
end
|
50
|
+
@redirect_count = 0
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# @private
|
55
|
+
#
|
56
|
+
# Perform the request
|
57
|
+
def execute(location = nil)
|
58
|
+
ensure_redirect_count!(location)
|
59
|
+
prepare_request
|
60
|
+
sign_request_if_needed
|
61
|
+
send_request(location || @uri)
|
62
|
+
handle_response
|
22
63
|
end
|
23
64
|
|
24
|
-
|
25
|
-
@redirect_count ||= 0
|
26
|
-
raise Errors::TooManyRedirects, "Max number of redirects #{@redirect_count} for #{uri}" if @redirect_count > max_redirect
|
65
|
+
private
|
27
66
|
|
28
|
-
|
67
|
+
def ensure_redirect_count!(location)
|
68
|
+
return if @redirect_count.zero?
|
69
|
+
return if @redirect_count <= @max_redirect
|
70
|
+
raise Errors::RedirectError.new(
|
71
|
+
"Max number of redirects #{@redirect_count} for #{@uri}",
|
72
|
+
location,
|
73
|
+
@redirect_count
|
74
|
+
)
|
75
|
+
end
|
29
76
|
|
30
|
-
|
77
|
+
def prepare_request
|
78
|
+
@http = HTTP.timeout(
|
31
79
|
:per_operation,
|
32
|
-
write: timeout,
|
33
|
-
connect: timeout,
|
34
|
-
read: timeout
|
35
|
-
).headers(headers)
|
80
|
+
write: @timeout,
|
81
|
+
connect: @timeout,
|
82
|
+
read: @timeout
|
83
|
+
).headers(@headers)
|
84
|
+
end
|
85
|
+
|
86
|
+
def log_request(method, uri)
|
87
|
+
return unless Namira.configure.log_requests
|
88
|
+
if defined?(::Rails)
|
89
|
+
Rails.logger.debug "#{method.to_s.upcase} - #{uri}"
|
90
|
+
else
|
91
|
+
STDOUT.puts "#{method.to_s.upcase} - #{uri}"
|
92
|
+
end
|
93
|
+
end
|
36
94
|
|
37
|
-
|
95
|
+
def send_request(location)
|
96
|
+
log_request(@method, location)
|
97
|
+
@response = @http.send(@method, location, body: @body)
|
98
|
+
rescue HTTP::TimeoutError => e
|
99
|
+
raise Namira::Errors::TimeoutError.new(e.message)
|
100
|
+
rescue Addressable::URI::InvalidURIError => e
|
101
|
+
raise Namira::Errors::InvalidURIError.new(e.message)
|
102
|
+
end
|
38
103
|
|
39
|
-
|
104
|
+
def sign_request_if_needed
|
105
|
+
@http = @auth.sign_request(@http, @redirect_count) unless @auth.nil?
|
106
|
+
end
|
40
107
|
|
41
|
-
|
108
|
+
def handle_response
|
109
|
+
case @response.status
|
42
110
|
when 200..299
|
43
|
-
|
111
|
+
create_response
|
44
112
|
when 301, 302
|
45
|
-
|
46
|
-
location = response.headers['Location']
|
47
|
-
raise Errors::RedirectError, 'Request redirected but no location was supplied' if location.nil?
|
48
|
-
send_request(location, method, headers, max_redirect, timeout, body, auth)
|
113
|
+
handle_redirect
|
49
114
|
else
|
50
|
-
|
115
|
+
create_error_response
|
51
116
|
end
|
117
|
+
end
|
52
118
|
|
53
|
-
|
54
|
-
|
119
|
+
def create_response
|
120
|
+
Namira::Response.new(@response)
|
55
121
|
end
|
56
122
|
|
57
|
-
|
123
|
+
def create_error_response
|
124
|
+
raise Errors::HTTPError.new("http_error/#{@response.status}", @response.status, create_response)
|
125
|
+
end
|
58
126
|
|
59
|
-
def
|
60
|
-
if
|
61
|
-
|
127
|
+
def handle_redirect
|
128
|
+
if @max_redirect == NO_FOLLOW_REDIRECT_COUNT
|
129
|
+
create_error_response
|
62
130
|
else
|
63
|
-
|
131
|
+
@redirect_count += 1
|
132
|
+
location = @response.headers['Location']
|
133
|
+
raise Errors::RedirectError.new('Request redirected but no location was supplied', nil, @redirect_count) if location.nil?
|
134
|
+
execute(location)
|
64
135
|
end
|
65
136
|
end
|
66
137
|
end
|
data/lib/namira/config.rb
CHANGED
@@ -1,25 +1,65 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
##
|
1
4
|
module Namira
|
2
|
-
|
3
|
-
|
5
|
+
##
|
6
|
+
# Namira configuration
|
7
|
+
#
|
8
|
+
# Namira.configure do |config|
|
9
|
+
# config.user_agent = "MyCoolApp"
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# @!attribute [rw] max_redirect
|
13
|
+
# The maximum number of redirects to follow before throwing a {Namira::Errors::RedirectError}
|
14
|
+
# @return [Integer] Defaults: 3
|
15
|
+
#
|
16
|
+
# @!attribute [rw] timeout
|
17
|
+
# The max length of time (in seconds) Namira will wait before canceling the request and
|
18
|
+
# throwing a {Namira::Errors::TimeoutError}
|
19
|
+
# @return [Float] Defaults: 5.0
|
20
|
+
#
|
21
|
+
# @!attribute [rw] backend
|
22
|
+
# The backend Namira will use to send the request.
|
23
|
+
# @return [Namira::Backend] This returns a Class and not an instance. Defaults: {Namira::Backend}
|
24
|
+
#
|
25
|
+
# @!attribute [rw] user_agent
|
26
|
+
# The string to send for the "User-Agent" header. The value set here will be overriden if a user agent is
|
27
|
+
# specified on the request itself.
|
28
|
+
# @return [String] Defaults: Namira/1.0
|
29
|
+
#
|
30
|
+
# @!attribute [r] headers
|
31
|
+
# Default headers to send with each request
|
32
|
+
# @return [OpenStruct]
|
33
|
+
#
|
34
|
+
# @!attribute [rw] log_requests
|
35
|
+
# Log requests using puts or Rails.logger.debug if it's defined
|
36
|
+
# @return (Bool) Defaults: true
|
37
|
+
class Config < OpenStruct
|
38
|
+
##
|
39
|
+
# The
|
40
|
+
# attr_accessor :max_redirect
|
41
|
+
# attr_accessor :timeout
|
42
|
+
# attr_accessor :backend
|
43
|
+
# attr_accessor :user_agent
|
4
44
|
|
5
45
|
DEFAULT_SETTINGS = {
|
6
46
|
max_redirect: 3,
|
7
47
|
timeout: 5.0,
|
8
48
|
backend: nil,
|
9
|
-
user_agent: "Namira/#{Namira::VERSION}"
|
49
|
+
user_agent: "Namira/#{Namira::VERSION}",
|
50
|
+
headers: OpenStruct.new,
|
51
|
+
log_requests: true
|
10
52
|
}.freeze
|
11
53
|
|
12
|
-
|
13
|
-
DEFAULT_SETTINGS.each do |k, v|
|
14
|
-
send("#{k}=", v)
|
15
|
-
end
|
16
|
-
end
|
54
|
+
private_constant :DEFAULT_SETTINGS
|
17
55
|
|
18
|
-
def
|
19
|
-
|
56
|
+
def initialize
|
57
|
+
super(DEFAULT_SETTINGS)
|
20
58
|
end
|
21
59
|
end
|
22
60
|
|
61
|
+
##
|
62
|
+
# The shared configuration
|
23
63
|
def self.configure
|
24
64
|
@config ||= Config.new
|
25
65
|
yield(@config) if block_given?
|
@@ -1,8 +1,24 @@
|
|
1
1
|
module Namira
|
2
2
|
module Errors
|
3
|
-
|
4
|
-
|
3
|
+
##
|
4
|
+
# HTTP Error
|
5
|
+
#
|
6
|
+
# Any non 2xx status code will raise this error.
|
7
|
+
class HTTPError < BaseError
|
8
|
+
##
|
9
|
+
# @return [Integer] The HTTP status that caused the error
|
10
|
+
attr_reader :status
|
5
11
|
|
12
|
+
##
|
13
|
+
# @return [Namira::Response] The HTTP response
|
14
|
+
attr_reader :response
|
15
|
+
|
16
|
+
##
|
17
|
+
# Returns a new instance of HTTPError
|
18
|
+
#
|
19
|
+
# @param msg [String] The error message. e.g. "http_error/500"
|
20
|
+
# @param status [Integer] The HTTP status that caused the error
|
21
|
+
# @param response [Namira::Response] The HTTP response
|
6
22
|
def initialize(msg, status, response)
|
7
23
|
@status = status
|
8
24
|
@response = response
|
@@ -1,6 +1,28 @@
|
|
1
1
|
module Namira
|
2
2
|
module Errors
|
3
|
-
|
3
|
+
##
|
4
|
+
# A RedirectError
|
5
|
+
#
|
6
|
+
# @!attribute [r] message
|
7
|
+
# @return [String] Will contain information about the error.
|
8
|
+
class RedirectError < BaseError
|
9
|
+
##
|
10
|
+
# The location the redirect is pointing to
|
11
|
+
# @return [String]
|
12
|
+
attr_reader :location
|
13
|
+
|
14
|
+
##
|
15
|
+
# The number of redirects that occured
|
16
|
+
# @return [Integer]
|
17
|
+
attr_reader :count
|
18
|
+
|
19
|
+
##
|
20
|
+
# Creates a new instance
|
21
|
+
def initialize(msg, location, count)
|
22
|
+
super(msg)
|
23
|
+
@location = location
|
24
|
+
@count = count
|
25
|
+
end
|
4
26
|
end
|
5
27
|
end
|
6
28
|
end
|
data/lib/namira/errors.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
|
-
require_relative 'errors/
|
1
|
+
require_relative 'errors/base_error'
|
2
2
|
require_relative 'errors/http_error'
|
3
|
-
require_relative 'errors/
|
3
|
+
require_relative 'errors/invalid_uri_error'
|
4
4
|
require_relative 'errors/redirect_error'
|
5
|
-
require_relative 'errors/
|
5
|
+
require_relative 'errors/timeout_error'
|
6
|
+
|
7
|
+
module Namira
|
8
|
+
##
|
9
|
+
# Namira Errors
|
10
|
+
module Errors
|
11
|
+
end
|
12
|
+
end
|
data/lib/namira/query_builder.rb
CHANGED
@@ -1,7 +1,22 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
1
3
|
module Namira
|
4
|
+
##
|
5
|
+
# Builds a query
|
6
|
+
#
|
7
|
+
# query = Namira::QueryBuilder.new
|
8
|
+
# query.name = 'Test Person'
|
9
|
+
# query.to_s
|
10
|
+
# => "name=Test%20Person"
|
2
11
|
class QueryBuilder < OpenStruct
|
12
|
+
##
|
13
|
+
# Returns the query as a valid query string
|
14
|
+
#
|
15
|
+
# @return [String]
|
3
16
|
def to_s
|
4
|
-
|
17
|
+
uri = Addressable::URI.new
|
18
|
+
uri.query_values = to_h
|
19
|
+
uri.query
|
5
20
|
end
|
6
21
|
end
|
7
22
|
end
|
data/lib/namira/request.rb
CHANGED
@@ -1,27 +1,52 @@
|
|
1
1
|
require 'http'
|
2
2
|
|
3
3
|
module Namira
|
4
|
+
##
|
5
|
+
# The request class is used to create and send HTTP requests.
|
6
|
+
#
|
7
|
+
# response = Namira::Request.new(uri: 'https://httpbin.org/headers').response
|
4
8
|
class Request
|
5
9
|
attr_reader :uri, :http_method
|
6
10
|
|
11
|
+
##
|
12
|
+
# Create a new request
|
13
|
+
#
|
14
|
+
# @param uri [String] The request URL
|
15
|
+
# @param http_method [Symbol] The HTTP method for the request. (Default `:get`)
|
16
|
+
# @param headers [Hash] Additional headers to send with the request. (Default: `{}`)
|
17
|
+
# @param body [String, #to_s] The body to send. (Default: nil)
|
18
|
+
# @param auth [Namira::Auth::Base] The auth instance used to sign requests.
|
19
|
+
# @param config [Hash] {Namira::Config} overrides
|
7
20
|
def initialize(uri:, http_method: :get, headers: {}, body: nil, auth: nil, config: {})
|
8
21
|
@uri = uri
|
9
22
|
@http_method = http_method
|
10
|
-
@headers = headers
|
23
|
+
@headers = Hash(headers)
|
11
24
|
@body = body
|
12
25
|
@auth = auth
|
13
26
|
@timeout = config[:timeout] || Namira.configure.timeout
|
14
27
|
@max_redirect = config[:max_redirect] || Namira.configure.max_redirect
|
15
28
|
@backend = config[:backend] || Namira.configure.backend || Namira::Backend
|
16
29
|
@user_agent = config[:user_agent] || Namira.configure.user_agent
|
30
|
+
@max_redirect = Backend::NO_FOLLOW_REDIRECT_COUNT if config[:follow_redirect] == false
|
17
31
|
end
|
18
32
|
|
33
|
+
##
|
34
|
+
# Sends the request.
|
35
|
+
#
|
36
|
+
# Every time this method is called a network request will be sent.
|
19
37
|
def send_request
|
20
|
-
@response
|
38
|
+
@response = _send_request(uri)
|
21
39
|
end
|
22
40
|
|
41
|
+
##
|
42
|
+
# The {Namira::Response} for the request.
|
43
|
+
#
|
44
|
+
# If the request hasn't been sent yet calling this will get the request.
|
45
|
+
#
|
46
|
+
# @return {Namira::Response}
|
23
47
|
def response
|
24
|
-
send_request
|
48
|
+
send_request if @response.nil?
|
49
|
+
@response
|
25
50
|
end
|
26
51
|
|
27
52
|
private
|
@@ -29,8 +54,8 @@ module Namira
|
|
29
54
|
def build_headers
|
30
55
|
{}.tap do |headers|
|
31
56
|
headers['User-Agent'] = @user_agent
|
32
|
-
Namira.configure.headers.each do |k, v|
|
33
|
-
key = k.split('_').map(&:capitalize).join('-')
|
57
|
+
Namira.configure.headers.to_h.each do |k, v|
|
58
|
+
key = k.to_s.split('_').map(&:capitalize).join('-')
|
34
59
|
headers[key] = v
|
35
60
|
end
|
36
61
|
@headers.each do |k, v|
|
data/lib/namira/response.rb
CHANGED
@@ -1,13 +1,33 @@
|
|
1
1
|
module Namira
|
2
|
+
##
|
3
|
+
# HTTP response
|
2
4
|
class Response
|
5
|
+
##
|
6
|
+
# Create a new {Namira::Response}
|
3
7
|
def initialize(backing)
|
4
8
|
@backing = backing
|
5
9
|
end
|
6
10
|
|
11
|
+
##
|
12
|
+
# @return [Hash, Array] Parse the response body as JSON
|
7
13
|
def from_json
|
8
14
|
@json ||= JSON.parse(@backing.body)
|
9
15
|
end
|
10
16
|
|
17
|
+
##
|
18
|
+
# @return [String] Returns the response as a string
|
19
|
+
def to_s
|
20
|
+
@backing.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# @return [Bool] If the response status 2xx
|
25
|
+
def ok?
|
26
|
+
(200...300).cover?(@backing.status)
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Proxies methods to the backing object
|
11
31
|
def method_missing(name, *args)
|
12
32
|
if @backing.respond_to?(name)
|
13
33
|
@backing.send(name, *args)
|
@@ -16,10 +36,6 @@ module Namira
|
|
16
36
|
end
|
17
37
|
end
|
18
38
|
|
19
|
-
def to_s
|
20
|
-
@backing.to_s
|
21
|
-
end
|
22
|
-
|
23
39
|
def respond_to_missing?(method_name, include_private = false)
|
24
40
|
@backing.respond_to?(method_name) || super
|
25
41
|
end
|
data/lib/namira/version.rb
CHANGED
data/lib/namira.rb
CHANGED
@@ -5,7 +5,9 @@ require 'namira/errors'
|
|
5
5
|
require 'namira/config'
|
6
6
|
require 'namira/query_builder'
|
7
7
|
require 'namira/backend'
|
8
|
-
require 'namira/extensions/hash_key_path'
|
9
8
|
require 'namira/auth'
|
10
9
|
|
11
|
-
|
10
|
+
##
|
11
|
+
# A Ruby HTTP client
|
12
|
+
module Namira
|
13
|
+
end
|
data/namira.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
lib = File.expand_path('../lib', __FILE__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require 'namira/version'
|
@@ -7,29 +6,25 @@ Gem::Specification.new do |spec|
|
|
7
6
|
spec.name = 'namira'
|
8
7
|
spec.version = Namira::VERSION
|
9
8
|
spec.authors = ['Skylar Schipper']
|
10
|
-
spec.email = ['
|
9
|
+
spec.email = ['me@skylarsch.com']
|
11
10
|
|
12
11
|
spec.summary = 'A simple wrapper around HTTP'
|
13
12
|
spec.description = 'This is a simple wrapper around HTTP'
|
14
13
|
spec.homepage = 'https://github.com/skylarsch/namira'
|
15
14
|
spec.license = 'MIT'
|
16
15
|
|
17
|
-
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
18
|
-
# delete this section to allow pushing this gem to any host.
|
19
|
-
if spec.respond_to?(:metadata)
|
20
|
-
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
21
|
-
else
|
22
|
-
raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
|
23
|
-
end
|
24
|
-
|
25
16
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
26
17
|
spec.bindir = 'exe'
|
27
18
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
19
|
spec.require_paths = ['lib']
|
29
20
|
|
30
|
-
spec.add_development_dependency 'bundler', '~> 1.15'
|
31
|
-
spec.add_development_dependency 'rake', '~> 10.0'
|
32
|
-
spec.add_development_dependency 'rspec', '~> 3.0'
|
33
|
-
spec.add_development_dependency 'pry'
|
34
21
|
spec.add_dependency 'http', '>= 2.0.0', '< 4.0'
|
22
|
+
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.15'
|
24
|
+
spec.add_development_dependency 'pry', '~> 0.11.3'
|
25
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
26
|
+
spec.add_development_dependency 'rspec', '~> 3.2'
|
27
|
+
spec.add_development_dependency 'simplecov', '~> 0.15'
|
28
|
+
spec.add_development_dependency 'webmock', '~> 3.3.0'
|
29
|
+
spec.add_development_dependency 'yard', '~> 0.9'
|
35
30
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: namira
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Skylar Schipper
|
@@ -10,6 +10,26 @@ bindir: exe
|
|
10
10
|
cert_chain: []
|
11
11
|
date: 2018-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: http
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.0.0
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '4.0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.0.0
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '4.0'
|
13
33
|
- !ruby/object:Gem::Dependency
|
14
34
|
name: bundler
|
15
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -24,6 +44,20 @@ dependencies:
|
|
24
44
|
- - "~>"
|
25
45
|
- !ruby/object:Gem::Version
|
26
46
|
version: '1.15'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: pry
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.11.3
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 0.11.3
|
27
61
|
- !ruby/object:Gem::Dependency
|
28
62
|
name: rake
|
29
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,59 +78,69 @@ dependencies:
|
|
44
78
|
requirements:
|
45
79
|
- - "~>"
|
46
80
|
- !ruby/object:Gem::Version
|
47
|
-
version: '3.
|
81
|
+
version: '3.2'
|
48
82
|
type: :development
|
49
83
|
prerelease: false
|
50
84
|
version_requirements: !ruby/object:Gem::Requirement
|
51
85
|
requirements:
|
52
86
|
- - "~>"
|
53
87
|
- !ruby/object:Gem::Version
|
54
|
-
version: '3.
|
88
|
+
version: '3.2'
|
55
89
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
90
|
+
name: simplecov
|
57
91
|
requirement: !ruby/object:Gem::Requirement
|
58
92
|
requirements:
|
59
|
-
- - "
|
93
|
+
- - "~>"
|
60
94
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
95
|
+
version: '0.15'
|
62
96
|
type: :development
|
63
97
|
prerelease: false
|
64
98
|
version_requirements: !ruby/object:Gem::Requirement
|
65
99
|
requirements:
|
66
|
-
- - "
|
100
|
+
- - "~>"
|
67
101
|
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
102
|
+
version: '0.15'
|
69
103
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
104
|
+
name: webmock
|
71
105
|
requirement: !ruby/object:Gem::Requirement
|
72
106
|
requirements:
|
73
|
-
- - "
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: 2.0.0
|
76
|
-
- - "<"
|
107
|
+
- - "~>"
|
77
108
|
- !ruby/object:Gem::Version
|
78
|
-
version:
|
79
|
-
type: :
|
109
|
+
version: 3.3.0
|
110
|
+
type: :development
|
80
111
|
prerelease: false
|
81
112
|
version_requirements: !ruby/object:Gem::Requirement
|
82
113
|
requirements:
|
83
|
-
- - "
|
114
|
+
- - "~>"
|
84
115
|
- !ruby/object:Gem::Version
|
85
|
-
version:
|
86
|
-
|
116
|
+
version: 3.3.0
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: yard
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
87
122
|
- !ruby/object:Gem::Version
|
88
|
-
version: '
|
123
|
+
version: '0.9'
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - "~>"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0.9'
|
89
131
|
description: This is a simple wrapper around HTTP
|
90
132
|
email:
|
91
|
-
-
|
133
|
+
- me@skylarsch.com
|
92
134
|
executables: []
|
93
135
|
extensions: []
|
94
136
|
extra_rdoc_files: []
|
95
137
|
files:
|
138
|
+
- ".circleci/config.yml"
|
96
139
|
- ".gitignore"
|
97
140
|
- ".rspec"
|
98
141
|
- ".rubocop.yml"
|
99
142
|
- ".travis.yml"
|
143
|
+
- CHANGELOG.md
|
100
144
|
- Gemfile
|
101
145
|
- LICENSE.txt
|
102
146
|
- README.md
|
@@ -110,12 +154,11 @@ files:
|
|
110
154
|
- lib/namira/backend.rb
|
111
155
|
- lib/namira/config.rb
|
112
156
|
- lib/namira/errors.rb
|
113
|
-
- lib/namira/errors/
|
157
|
+
- lib/namira/errors/base_error.rb
|
114
158
|
- lib/namira/errors/http_error.rb
|
159
|
+
- lib/namira/errors/invalid_uri_error.rb
|
115
160
|
- lib/namira/errors/redirect_error.rb
|
116
|
-
- lib/namira/errors/
|
117
|
-
- lib/namira/errors/too_many_redirects.rb
|
118
|
-
- lib/namira/extensions/hash_key_path.rb
|
161
|
+
- lib/namira/errors/timeout_error.rb
|
119
162
|
- lib/namira/query_builder.rb
|
120
163
|
- lib/namira/request.rb
|
121
164
|
- lib/namira/response.rb
|
@@ -124,8 +167,7 @@ files:
|
|
124
167
|
homepage: https://github.com/skylarsch/namira
|
125
168
|
licenses:
|
126
169
|
- MIT
|
127
|
-
metadata:
|
128
|
-
allowed_push_host: https://rubygems.org
|
170
|
+
metadata: {}
|
129
171
|
post_install_message:
|
130
172
|
rdoc_options: []
|
131
173
|
require_paths:
|
@@ -137,9 +179,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
137
179
|
version: '0'
|
138
180
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
139
181
|
requirements:
|
140
|
-
- - "
|
182
|
+
- - ">"
|
141
183
|
- !ruby/object:Gem::Version
|
142
|
-
version:
|
184
|
+
version: 1.3.1
|
143
185
|
requirements: []
|
144
186
|
rubyforge_project:
|
145
187
|
rubygems_version: 2.6.13
|
data/lib/namira/errors/base.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
module Namira
|
2
|
-
module Extensions
|
3
|
-
module HashKeyPath
|
4
|
-
def value_for_key_path(path)
|
5
|
-
components = path.split('.')
|
6
|
-
value = self
|
7
|
-
components.each do |key|
|
8
|
-
break if value.nil?
|
9
|
-
|
10
|
-
value = case value
|
11
|
-
when Hash
|
12
|
-
value[key] || value[key.to_sym]
|
13
|
-
when Array
|
14
|
-
value[key.to_i]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
value
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|