aitch 1.2.2 → 2.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c49091163504e6a6587170951f8e4545b4474b1912c85c5bcfeb102763a214b7
4
- data.tar.gz: 7fac91b61ee9ad82e8f880f25758b9f6a433ad8ed3bcc5134b261e64f5da61fc
3
+ metadata.gz: 722d82e16f8558e3b413e03aee56424d1975de6ff41b9dd6493a86f5fd02e94a
4
+ data.tar.gz: 300f21a267ba36d3ba6b8c0b7e3e2db4ce7477daa0527253673b7c38c06a538b
5
5
  SHA512:
6
- metadata.gz: 859bdbfb5f70d99646c628f16a2cea718385299ca1b48d32e0ecfb8c9598ad27b8cf3363498b50eaddf8585901212faa1f588dc9dc29ad1982891f2a3c26b1fa
7
- data.tar.gz: a7045d8d2a6c9d172b2b90180cd4d2afb13a5ceac088b74b9cb7ccc63fa9050920df69310e0eef1ae745b44d0edd4c45f6779c9a6fe420c3951878be4ff3fbf1
6
+ metadata.gz: 57e36cb6a2dbfd023dbc2c32fb4c56387bbfda4d23de23073bcd2e0db687e2b7e78f180203df7b963754c7fe2f360f69a76bc6679f97cf0cbd418621b27b496e
7
+ data.tar.gz: 51b3b156046f961169b3ce28659458f75d8559f6b404d12e4c48b420f556e9bf03b06311bfad4cda47c46f32c36b47989b54aa8c8318eda4136d619c63325165
@@ -15,12 +15,12 @@ jobs:
15
15
  strategy:
16
16
  fail-fast: false
17
17
  matrix:
18
- ruby: ["2.7.x", "2.6.x", "2.5.x", "3.0.x", "3.1.x"]
18
+ ruby: ["3.0", "3.1", "3.2"]
19
19
 
20
20
  steps:
21
- - uses: actions/checkout@v1
21
+ - uses: actions/checkout@v4
22
22
 
23
- - uses: actions/cache@v2
23
+ - uses: actions/cache@v3
24
24
  with:
25
25
  path: vendor/bundle
26
26
  key: >
@@ -31,7 +31,7 @@ jobs:
31
31
  hashFiles('aitch.gemspec') }}
32
32
 
33
33
  - name: Set up Ruby
34
- uses: actions/setup-ruby@v1
34
+ uses: ruby/setup-ruby@v1
35
35
  with:
36
36
  ruby-version: ${{ matrix.ruby }}
37
37
 
data/.rubocop.yml CHANGED
@@ -3,7 +3,7 @@ inherit_gem:
3
3
  rubocop-fnando: .rubocop.yml
4
4
 
5
5
  AllCops:
6
- TargetRubyVersion: 2.5
6
+ TargetRubyVersion: 3.0
7
7
  NewCops: enable
8
8
 
9
9
  Layout/LineLength:
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ - **2.1.0**
4
+ - Add support for retries.
5
+ - Change headers to have its own class, abstracting keys (strings, symbols,
6
+ casing).
7
+ - Move core extensions to refinements.
8
+ - **2.0.0**
9
+ - Fix error when content type is not available on response.
10
+ - Stop supporting old ruby versions (require 3.0+).
3
11
  - **1.2.2**
4
12
  - Transform header key before assigning values.
5
13
  - **1.2.1**
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Aitch
2
2
 
3
- [![Tests](https://github.com/fnando/aitch/workflows/Tests/badge.svg)](https://github.com/fnando/aitch)
3
+ [![Tests](https://github.com/fnando/aitch/actions/workflows/tests.yml/badge.svg)](https://github.com/fnando/aitch/actions/workflows/tests.yml)
4
4
  [![Code Climate](https://codeclimate.com/github/fnando/aitch/badges/gpa.svg)](https://codeclimate.com/github/fnando/aitch)
5
5
  [![Gem Version](https://img.shields.io/gem/v/aitch.svg)](https://rubygems.org/gems/aitch)
6
6
  [![Gem Downloads](https://img.shields.io/gem/dt/aitch.svg)](https://rubygems.org/gems/aitch)
@@ -43,6 +43,11 @@ Aitch.configure do |config|
43
43
  # Set default headers.
44
44
  config.default_headers = {}
45
45
 
46
+ # Set number of retries.
47
+ # See Net::HTTP#max_retries to know which errors trigger a new request
48
+ # attempt.
49
+ config.retries = 1
50
+
46
51
  # Set follow redirect.
47
52
  config.follow_redirect = true
48
53
 
data/aitch.gemspec CHANGED
@@ -11,16 +11,18 @@ Gem::Specification.new do |spec|
11
11
  spec.summary = spec.description
12
12
  spec.homepage = "http://rubygems.org/gems/aitch"
13
13
  spec.license = "MIT"
14
- spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
14
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.0.0")
15
15
  spec.metadata["rubygems_mfa_required"] = "true"
16
16
 
17
17
  spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
18
18
  spec.executables = spec.files.grep(%r{^bin/}) {|f| File.basename(f) }
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_dependency "base64"
21
22
  spec.add_dependency "nokogiri"
22
23
 
23
24
  spec.add_development_dependency "bundler"
25
+ spec.add_development_dependency "csv"
24
26
  spec.add_development_dependency "minitest"
25
27
  spec.add_development_dependency "minitest-utils"
26
28
  spec.add_development_dependency "mocha"
@@ -9,7 +9,7 @@ module Aitch
9
9
  attr_accessor :timeout
10
10
 
11
11
  # Set default headers.
12
- attr_accessor :default_headers
12
+ attr_reader :default_headers
13
13
 
14
14
  # Set follow redirect.
15
15
  attr_accessor :follow_redirect
@@ -17,6 +17,20 @@ module Aitch
17
17
  # Set redirection limit.
18
18
  attr_accessor :redirect_limit
19
19
 
20
+ # Set number of retries. This will be set as `Net::HTTP#max_retries`.
21
+ # Defaults to 1 (ruby's default). Retries are triggered for the following
22
+ # errors:
23
+ #
24
+ # - `Net::ReadTimeout`
25
+ # - `IOError`
26
+ # - `EOFError`
27
+ # - `Errno::ECONNRESET`
28
+ # - `Errno::ECONNABORTED`
29
+ # - `Errno::EPIPE`
30
+ # - `OpenSSL::SSL::SSLError`
31
+ # - `Timeout::Error`
32
+ attr_accessor :retries
33
+
20
34
  # Set the user agent.
21
35
  attr_accessor :user_agent
22
36
 
@@ -28,13 +42,18 @@ module Aitch
28
42
 
29
43
  def initialize
30
44
  @timeout = 10
45
+ @retries = 1
31
46
  @redirect_limit = 5
32
47
  @follow_redirect = true
33
48
  @user_agent = "Aitch/#{Aitch::VERSION} (http://rubygems.org/gems/aitch)"
34
- @default_headers = {}
49
+ @default_headers = Headers.new
35
50
  @base_url = nil
36
51
  end
37
52
 
53
+ def default_headers=(headers)
54
+ @default_headers = Headers.new(headers)
55
+ end
56
+
38
57
  def to_h
39
58
  instance_variables.each_with_object({}) do |name, buffer|
40
59
  buffer[name.to_s.tr("@", "").to_sym] = instance_variable_get(name)
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aitch
4
+ module Ext
5
+ refine String do
6
+ def dasherize
7
+ unicode_normalize(:nfkd)
8
+ .delete("'")
9
+ .gsub(/[^\x00-\x7F]/, "")
10
+ .gsub(/([a-z\d])([A-Z])/, '\1-\2')
11
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1-\2')
12
+ .gsub(/[^-\w]+/xim, "-")
13
+ .tr("_", "-")
14
+ .gsub(/-+/xm, "-")
15
+ .gsub(/^-?(.*?)-?$/, '\1')
16
+ .downcase
17
+ end
18
+ end
19
+ end
20
+ end
@@ -2,80 +2,84 @@
2
2
 
3
3
  require "cgi"
4
4
 
5
- class Object
6
- # Alias of <tt>to_s</tt>.
7
- def to_param
8
- to_s
9
- end
5
+ module Aitch
6
+ module Ext
7
+ refine Object do
8
+ # Alias of <tt>to_s</tt>.
9
+ def to_param
10
+ to_s
11
+ end
10
12
 
11
- # Converts an object into a string suitable for use as a URL query string,
12
- # using the given <tt>key</tt> as the param name.
13
- def to_query(key)
14
- "#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}"
15
- end
16
- end
13
+ # Converts an object into a string suitable for use as a URL query string,
14
+ # using the given <tt>key</tt> as the param name.
15
+ def to_query(key)
16
+ "#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}"
17
+ end
18
+ end
17
19
 
18
- class NilClass
19
- # Returns +self+.
20
- def to_param
21
- self
22
- end
23
- end
20
+ refine NilClass do
21
+ # Returns +self+.
22
+ def to_param
23
+ self
24
+ end
25
+ end
24
26
 
25
- class TrueClass
26
- # Returns +self+.
27
- def to_param
28
- self
29
- end
30
- end
27
+ refine TrueClass do
28
+ # Returns +self+.
29
+ def to_param
30
+ self
31
+ end
32
+ end
31
33
 
32
- class FalseClass
33
- # Returns +self+.
34
- def to_param
35
- self
36
- end
37
- end
34
+ refine FalseClass do
35
+ # Returns +self+.
36
+ def to_param
37
+ self
38
+ end
39
+ end
38
40
 
39
- class Array
40
- # Converts an array into a string suitable for use as a URL query string,
41
- # using the given +key+ as the param name.
42
- #
43
- # ["Rails", "coding"].to_query("hobbies")
44
- # # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
45
- def to_query(key)
46
- prefix = "#{key}[]"
41
+ refine Array do
42
+ # Converts an array into a string suitable for use as a URL query string,
43
+ # using the given +key+ as the param name.
44
+ #
45
+ # ["Rails", "coding"].to_query("hobbies")
46
+ # # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
47
+ def to_query(key)
48
+ prefix = "#{key}[]"
47
49
 
48
- if empty?
49
- nil.to_query(prefix)
50
- else
51
- collect {|value| value.to_query(prefix) }.join "&"
50
+ if empty?
51
+ nil.to_query(prefix)
52
+ else
53
+ collect {|value| value.to_query(prefix) }.join "&"
54
+ end
55
+ end
52
56
  end
53
- end
54
- end
55
57
 
56
- class Hash
57
- # Returns a string representation of the receiver suitable for use as a URL
58
- # query string:
59
- #
60
- # {name: 'David', nationality: 'Danish'}.to_query
61
- # # => "name=David&nationality=Danish"
62
- #
63
- # An optional namespace can be passed to enclose key names:
64
- #
65
- # {name: 'David', nationality: 'Danish'}.to_query('user')
66
- # # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
67
- #
68
- # The string pairs "key=value" that conform the query string
69
- # are sorted lexicographically in ascending order.
70
- #
71
- # This method is also aliased as +to_param+.
72
- def to_query(namespace = nil)
73
- collect do |key, value|
74
- unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
75
- value.to_query(namespace ? "#{namespace}[#{key}]" : key)
58
+ refine Hash do
59
+ # Returns a string representation of the receiver suitable for use as a URL
60
+ # query string:
61
+ #
62
+ # {name: 'David', nationality: 'Danish'}.to_query
63
+ # # => "name=David&nationality=Danish"
64
+ #
65
+ # An optional namespace can be passed to enclose key names:
66
+ #
67
+ # {name: 'David', nationality: 'Danish'}.to_query('user')
68
+ # # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
69
+ #
70
+ # The string pairs "key=value" that conform the query string
71
+ # are sorted lexicographically in ascending order.
72
+ #
73
+ # This method is also aliased as +to_param+.
74
+ def to_query(namespace = nil)
75
+ filter_map do |key, value|
76
+ unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
77
+ value.to_query(namespace ? "#{namespace}[#{key}]" : key)
78
+ end
79
+ end.sort! * "&"
76
80
  end
77
- end.compact.sort! * "&"
78
- end
79
81
 
80
- alias to_param to_query
82
+ alias_method :to_param, :to_query
83
+ end
84
+ end
81
85
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Aitch
4
+ class Headers
5
+ extend Forwardable
6
+ include Enumerable
7
+
8
+ using Ext
9
+
10
+ def_delegators :@store, :each, :empty?, :any?
11
+
12
+ def initialize(input = {})
13
+ @store = {}
14
+ input.to_h.each {|key, value| self[key] = value }
15
+ end
16
+
17
+ def delete(key)
18
+ @store.delete(normalize_key(key))
19
+ end
20
+
21
+ def [](key)
22
+ @store[normalize_key(key)]
23
+ end
24
+
25
+ def []=(key, value)
26
+ @store[normalize_key(key)] = value
27
+ end
28
+
29
+ def key?(key)
30
+ @store.key?(normalize_key(key))
31
+ end
32
+
33
+ def ==(other)
34
+ @store == Headers.new(other).to_h
35
+ end
36
+
37
+ def to_h
38
+ @store.dup
39
+ end
40
+
41
+ private def normalize_key(key)
42
+ key.to_s.dasherize
43
+ end
44
+ end
45
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Aitch
4
4
  class Location
5
- MATCHER = %r{\A/}.freeze
5
+ MATCHER = %r{\A/}
6
6
 
7
7
  attr_reader :redirect_stack, :current_url
8
8
 
data/lib/aitch/request.rb CHANGED
@@ -2,21 +2,21 @@
2
2
 
3
3
  module Aitch
4
4
  class Request
5
- attr_accessor :request_method, :url, :data, :headers, :options, :redirects
5
+ attr_accessor :request_method, :url, :data, :options, :redirects
6
+ attr_reader :headers
6
7
 
7
- CONTENT_TYPE = "Content-Type"
8
- USER_AGENT = "User-Agent"
9
- ACCEPT_ENCODING = "Accept-Encoding"
8
+ CONTENT_TYPE = "content-type"
9
+ USER_AGENT = "user-agent"
10
+ ACCEPT_ENCODING = "accept-encoding"
10
11
  GZIP_DEFLATE = "gzip,deflate"
11
12
  HTTPS = "https"
12
- HEADER_SEPARATOR_RE = /[-_]/.freeze
13
- JSON_RE = /\bjson\b/.freeze
13
+ JSON_RE = /\bjson\b/
14
14
 
15
15
  alias params= data=
16
16
  alias body= data=
17
17
 
18
18
  def initialize(options)
19
- self.headers = {}
19
+ @headers = Headers.new
20
20
  self.options = {}
21
21
  self.redirects = []
22
22
 
@@ -27,6 +27,10 @@ module Aitch
27
27
  end
28
28
  end
29
29
 
30
+ def headers=(headers)
31
+ @headers = Headers.new(headers)
32
+ end
33
+
30
34
  def perform
31
35
  response = Response.new(options, client.request(request))
32
36
  response.url = url
@@ -43,7 +47,7 @@ module Aitch
43
47
 
44
48
  def content_type
45
49
  headers[CONTENT_TYPE] ||
46
- options.fetch(:default_headers, {})[CONTENT_TYPE]
50
+ Headers.new(options.fetch(:default_headers, {}))[CONTENT_TYPE]
47
51
  end
48
52
 
49
53
  def request
@@ -60,6 +64,7 @@ module Aitch
60
64
  @client ||= Net::HTTP.new(uri.host, uri.port).tap do |client|
61
65
  set_https(client)
62
66
  set_timeout(client)
67
+ set_max_retries(client)
63
68
  set_logger(client)
64
69
  end
65
70
  end
@@ -99,11 +104,12 @@ module Aitch
99
104
  end
100
105
 
101
106
  private def set_headers(request)
102
- all_headers = options.fetch(:default_headers, {}).merge(headers)
107
+ all_headers = Headers.new(options.fetch(:default_headers, {}))
108
+ .to_h
109
+ .merge(headers.to_h)
103
110
 
104
111
  all_headers.each do |name, value|
105
- value = value.respond_to?(:call) ? value.call : value
106
- name = name.to_s.split(HEADER_SEPARATOR_RE).map(&:capitalize).join("-")
112
+ value = value.call if value.respond_to?(:call)
107
113
  request[name] = value.to_s
108
114
  end
109
115
  end
@@ -136,6 +142,10 @@ module Aitch
136
142
  request[ACCEPT_ENCODING] = GZIP_DEFLATE
137
143
  end
138
144
 
145
+ private def set_max_retries(client)
146
+ client.max_retries = options.fetch(:retries, 1)
147
+ end
148
+
139
149
  def timeout_exception
140
150
  defined?(Net::ReadTimeout) ? Net::ReadTimeout : Timeout::Error
141
151
  end
@@ -2,8 +2,6 @@
2
2
 
3
3
  module Aitch
4
4
  class Response
5
- extend Forwardable
6
-
7
5
  JSON_STR = "json"
8
6
  XML_STR = "xml"
9
7
  HTML_STR = "html"
@@ -11,10 +9,9 @@ module Aitch
11
9
  DOUBLE_COLON = "::"
12
10
  SPACE_STR = " "
13
11
  ERROR_SUFFIX = "_error"
14
- X_RE = /^x-/.freeze
12
+ X_RE = /^x-/
15
13
 
16
- def_delegators :@http_response, :content_type
17
- attr_accessor :redirected_from, :url
14
+ attr_accessor :redirected_from, :url, :content_type
18
15
 
19
16
  def self.description_for_code(code)
20
17
  [code, DESCRIPTION[code]].compact.join(SPACE_STR)
@@ -24,6 +21,7 @@ module Aitch
24
21
  @options = options
25
22
  @http_response = http_response
26
23
  @redirected_from = options.fetch(:redirected_from, [])
24
+ @content_type = http_response.content_type.to_s
27
25
  end
28
26
 
29
27
  ERRORS.each do |status_code, exception|
data/lib/aitch/utils.rb CHANGED
@@ -4,7 +4,9 @@ module Aitch
4
4
  module Utils
5
5
  extend self
6
6
 
7
- MATCHER = /(?<=.)(URI|[A-Z])/.freeze
7
+ using Ext
8
+
9
+ MATCHER = /(?<=.)(URI|[A-Z])/
8
10
 
9
11
  def underscore(string)
10
12
  string = string.gsub(MATCHER) do |char|
data/lib/aitch/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Aitch
4
- VERSION = "1.2.2"
4
+ VERSION = "2.1.0"
5
5
  end
data/lib/aitch.rb CHANGED
@@ -16,8 +16,10 @@ end
16
16
  require "aitch/utils"
17
17
  require "aitch/uri"
18
18
  require "aitch/dsl"
19
+ require "aitch/ext/string"
19
20
  require "aitch/namespace"
20
21
  require "aitch/location"
22
+ require "aitch/headers"
21
23
  require "aitch/configuration"
22
24
  require "aitch/errors"
23
25
  require "aitch/engines/json"
@@ -7,6 +7,10 @@ class ConfigurationTest < Minitest::Test
7
7
  assert_equal 10, Aitch::Configuration.new.timeout
8
8
  end
9
9
 
10
+ test "sets default retries" do
11
+ assert_equal 1, Aitch::Configuration.new.retries
12
+ end
13
+
10
14
  test "sets default user agent" do
11
15
  user_agent = "Aitch/#{Aitch::VERSION} (http://rubygems.org/gems/aitch)"
12
16
 
@@ -18,7 +22,10 @@ class ConfigurationTest < Minitest::Test
18
22
  end
19
23
 
20
24
  test "sets default headers" do
21
- assert_empty(Aitch::Configuration.new.default_headers)
25
+ config = Aitch::Configuration.new
26
+ config.default_headers = {content_type: "application/json"}
27
+
28
+ assert_equal({"content-type" => "application/json"}, config.default_headers.to_h)
22
29
  end
23
30
 
24
31
  test "configures aitch" do
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ class HeadersTest < Minitest::Test
6
+ let(:headers) { Aitch::Headers.new }
7
+
8
+ test "normalizes header name" do
9
+ headers[:content_type] = "application/json"
10
+
11
+ assert_equal "application/json", headers["Content-Type"]
12
+ assert_equal "application/json", headers[:content_type]
13
+ assert_equal "application/json", headers["content-type"]
14
+ assert_equal({"content-type" => "application/json"}, headers.to_h)
15
+ assert headers == {"content-type" => "application/json"} # rubocop:disable Minitest/AssertEqual, Minitest/AssertOperator
16
+ end
17
+
18
+ test "implements key?" do
19
+ headers[:content_type] = "application/json"
20
+
21
+ assert headers.key?("Content-Type")
22
+ assert headers.key?("content-type")
23
+ assert headers.key?(:content_type)
24
+ end
25
+
26
+ test "implements empty?" do
27
+ assert_empty headers
28
+ end
29
+
30
+ test "implements any?" do
31
+ refute headers.any?
32
+ end
33
+
34
+ test "implements delete" do
35
+ headers[:content_type] = "application/json"
36
+ headers.delete("Content-Type")
37
+
38
+ assert_empty headers
39
+ end
40
+ end
@@ -9,6 +9,13 @@ class RequestTest < Minitest::Test
9
9
  assert_equal "application/json", request.content_type
10
10
  end
11
11
 
12
+ test "sets retries" do
13
+ request = build_request(options: {retries: 3})
14
+
15
+ assert_equal 3, request.options[:retries]
16
+ assert_equal 3, request.client.max_retries
17
+ end
18
+
12
19
  test "raises with invalid uri" do
13
20
  assert_raises(Aitch::InvalidURIError) { build_request(url: "\\").uri }
14
21
  end
@@ -139,7 +146,7 @@ class RequestTest < Minitest::Test
139
146
  test "sets headers from underscored headers" do
140
147
  request = build_request(headers: {content_type: "text/plain"}).request
141
148
 
142
- assert_equal "text/plain", request["Content-Type"]
149
+ assert_equal "text/plain", request["content-type"]
143
150
  end
144
151
 
145
152
  test "executes headers with callable protocol" do
@@ -150,7 +157,7 @@ class RequestTest < Minitest::Test
150
157
 
151
158
  test "sets basic auth credentials" do
152
159
  request = build_request(options: {user: "USER", password: "PASS"}).request
153
- credentials = Base64.decode64(request["Authorization"].gsub(/Basic /, ""))
160
+ credentials = Base64.decode64(request["Authorization"].gsub("Basic ", ""))
154
161
 
155
162
  assert_equal "USER:PASS", credentials
156
163
  end
@@ -8,7 +8,7 @@ class ErrorsTest < Minitest::Test
8
8
 
9
9
  test "detects response as #{name}" do
10
10
  config = {}
11
- http_response = stub(code: code)
11
+ http_response = stub(code: code, content_type: "text/html")
12
12
  response = Aitch::Response.new(config, http_response)
13
13
 
14
14
  assert response.public_send("#{name}?")
@@ -6,11 +6,20 @@ class Status3xxTest < Minitest::Test
6
6
  setup { Aitch.configuration.follow_redirect = false }
7
7
 
8
8
  test "sets default redirected from" do
9
- assert_empty Aitch::Response.new({}, stub("response")).redirected_from
9
+ response =
10
+ Aitch::Response.new({}, stub("response", content_type: "text/html"))
11
+
12
+ assert_empty response.redirected_from
10
13
  end
11
14
 
12
15
  test "uses provided redirected from" do
13
- assert_equal ["URL"], Aitch::Response.new({redirected_from: ["URL"]}, stub("response")).redirected_from
16
+ response =
17
+ Aitch::Response.new(
18
+ {redirected_from: ["URL"]},
19
+ stub("response", content_type: "text/html")
20
+ )
21
+
22
+ assert_equal ["URL"], response.redirected_from
14
23
  end
15
24
 
16
25
  test "has body" do
@@ -11,7 +11,7 @@ class XmlParserTest < Minitest::Test
11
11
  test "converts ISO-8859-1 to UTF-8" do
12
12
  xml = Aitch::ResponseParser::XMLParser.load(File.read("./test/fixtures/iso8859-1.xml"))
13
13
 
14
- assert_equal "utf-8", xml.encoding
15
- assert_includes xml.to_xml, %[<?xml version="1.0" encoding="utf-8"?>]
14
+ assert_match "UTF-8", xml.encoding
15
+ assert_includes xml.to_xml, %[<?xml version="1.0" encoding="UTF-8"?>]
16
16
  end
17
17
  end
@@ -3,6 +3,8 @@
3
3
  require "test_helper"
4
4
 
5
5
  class ToQueryTest < Minitest::Test
6
+ using Aitch::Ext
7
+
6
8
  test "converts array" do
7
9
  assert_equal "hobbies%5B%5D=Rails&hobbies%5B%5D=coding",
8
10
  %w[Rails coding].to_query("hobbies")
@@ -9,14 +9,13 @@ module Minitest
9
9
  def register_uri(http_method, url, options = {})
10
10
  body = options.fetch(:body, "")
11
11
  status = options.fetch(:status, 200)
12
- headers = options.fetch(:headers, {})
12
+ headers = options.fetch(:headers, Aitch::Headers.new)
13
13
 
14
14
  add_hash_entry(options, headers, :location, "Location")
15
15
  add_hash_entry(options, headers, :content_type, "Content-Type")
16
16
  add_hash_entry(options, headers, :content_encoding, "Content-Encoding")
17
17
 
18
- stub_request(http_method, url)
19
- .to_return(status: status, body: body, headers: headers)
18
+ stub_request(http_method, url).to_return(status:, body:, headers:)
20
19
  end
21
20
 
22
21
  def last_request
metadata CHANGED
@@ -1,15 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aitch
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nando Vieira
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-02-02 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: base64
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
13
26
  - !ruby/object:Gem::Dependency
14
27
  name: nokogiri
15
28
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +51,20 @@ dependencies:
38
51
  - - ">="
39
52
  - !ruby/object:Gem::Version
40
53
  version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: csv
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
41
68
  - !ruby/object:Gem::Dependency
42
69
  name: minitest
43
70
  requirement: !ruby/object:Gem::Requirement
@@ -186,7 +213,9 @@ files:
186
213
  - lib/aitch/dsl.rb
187
214
  - lib/aitch/engines/json.rb
188
215
  - lib/aitch/errors.rb
216
+ - lib/aitch/ext/string.rb
189
217
  - lib/aitch/ext/to_query.rb
218
+ - lib/aitch/headers.rb
190
219
  - lib/aitch/location.rb
191
220
  - lib/aitch/namespace.rb
192
221
  - lib/aitch/redirect.rb
@@ -207,6 +236,7 @@ files:
207
236
  - test/aitch/configuration_test.rb
208
237
  - test/aitch/dsl_test.rb
209
238
  - test/aitch/execute_test.rb
239
+ - test/aitch/headers_test.rb
210
240
  - test/aitch/namespace_test.rb
211
241
  - test/aitch/request/client_https_test.rb
212
242
  - test/aitch/request/follow_redirect_test.rb
@@ -240,7 +270,6 @@ licenses:
240
270
  - MIT
241
271
  metadata:
242
272
  rubygems_mfa_required: 'true'
243
- post_install_message:
244
273
  rdoc_options: []
245
274
  require_paths:
246
275
  - lib
@@ -248,15 +277,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
248
277
  requirements:
249
278
  - - ">="
250
279
  - !ruby/object:Gem::Version
251
- version: 2.5.0
280
+ version: 3.0.0
252
281
  required_rubygems_version: !ruby/object:Gem::Requirement
253
282
  requirements:
254
283
  - - ">="
255
284
  - !ruby/object:Gem::Version
256
285
  version: '0'
257
286
  requirements: []
258
- rubygems_version: 3.4.3
259
- signing_key:
287
+ rubygems_version: 3.6.9
260
288
  specification_version: 4
261
289
  summary: A simple HTTP client
262
290
  test_files: []