namira 0.2.1 → 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/namira.svg)](https://badge.fury.io/rb/namira)
|
4
|
+
[![CircleCI](https://circleci.com/gh/skylarsch/namira/tree/master.svg?style=svg)](https://circleci.com/gh/skylarsch/namira/tree/master)
|
5
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/888de458aae02d3c7cfc/maintainability)](https://codeclimate.com/github/skylarsch/namira/maintainability)
|
6
|
+
[![Test Coverage](https://api.codeclimate.com/v1/badges/888de458aae02d3c7cfc/test_coverage)](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
|