ethon 0.7.3 → 0.7.4

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,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MzIwZTI3ZDU0NzcyNGIwYTcyNDQwMzBhMTE3YWVjOTk4M2NmODg3Yg==
4
+ N2ZmZmIxYjlmYzhiMDJmODM5YjczNWE5NGQwYTA1OTIzMTU2YTQ5YQ==
5
5
  data.tar.gz: !binary |-
6
- ODA0NWYyYWJmMWJiZTExN2JlNmY4YmI4ZDM4YTEzOTkwNzNhODM5MA==
6
+ YThkNDc2ZmViYTdlZDkxNWUxMjRiNmE5NzIyNDUyN2QxMDlkNDc2MA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- NTk5ZjIxNjQ4NDVmYTkzMGE2NDBjNTA2MTI5MzA3ODE4NjA2Mzg2MjkzNzk5
10
- NGNhMmEzNjBiODc3OGQ2OTZmNzUwNmI2ZTVmZjVjYjk2YjA5OThjYzM0MzA2
11
- YWE2OTBiODZiZGJjOTA3YjdjMWY5YTVmNGRjOTgwYTBjMDQwYjc=
9
+ ZjZjYTk3OGM3MGNlMmU3YmJiMGNkM2ZhMGE3MGRlNWUyYmYzMjFkOTRjNmVj
10
+ YWY1NzBmZTIyYTFlY2I2M2ZlMzhmMDk1ZWJiNDk2MDlhODJhMTg1ZWVhM2Yy
11
+ MjM5ODJjNWI0MTY3MWU0NzkxZTFkNWQ0YTdkZGJhMmY1YzdmYzc=
12
12
  data.tar.gz: !binary |-
13
- NTgzMzlkN2Q3YTY5YWIyMWRmNzdlMDFjZGFkZTdkOTYyNjZkMWI3ZTEyMGRi
14
- NTA2ODhhMjdjYmYwOTg2MDNlMjVlZmUzZWIzNGExODg1YzNmN2MwNGQ5ZGJi
15
- ZTIzNjllMmQzYzczMGI3MTIxYzA2NWViNmU4ZWI0MDJkMTU3ODg=
13
+ MmZiN2MxYmQyYmM4YWExOTIxYzU4NDlkYWRhYmE0M2RlZWIzOGJlY2IwOThm
14
+ MzkyZGQ0OGMzOTQyZWE0ZjZhODU5ZTlkMjk3ZWFjZGI2Y2E0NzZiOTM3ZjFl
15
+ NTkyMzYzNDQ2NWRjY2FkOWJjMDVjZGFkZmRmZDE3ZmI3ZjRmYTg=
@@ -2,7 +2,17 @@
2
2
 
3
3
  ## Master
4
4
 
5
- [Full Changelog](https://github.com/typhoeus/ethon/compare/v0.7.3...master)
5
+ [Full Changelog](https://github.com/typhoeus/ethon/compare/v0.7.4...master)
6
+
7
+ ## 0.7.4
8
+
9
+ [Full Changelog](https://github.com/typhoeus/ethon/compare/v0.7.3...v0.7.4)
10
+
11
+ * Support different array encodings for params.
12
+ ([Marcello Barnaba](https://github.com/ifad), [\#104](https://github.com/typhoeus/ethon/pull/104))
13
+ * Programtic access to version infos.
14
+ ([Jonas Wagner](https://github.com/jwagner), [\#90](https://github.com/typhoeus/ethon/pull/90))
15
+
6
16
 
7
17
  ## 0.7.3
8
18
 
@@ -10,6 +10,18 @@ module Ethon
10
10
  layout :code, :msg_code, :easy_handle, :pointer, :data, MsgData
11
11
  end
12
12
 
13
+ class VersionInfoData < ::FFI::Struct
14
+ layout :curl_version, :uint8,
15
+ :version, :string,
16
+ :version_num, :int,
17
+ :host, :string,
18
+ :features, :int,
19
+ :ssl_version, :string,
20
+ :ssl_version_num, :long,
21
+ :libz_version, :string,
22
+ :protocols, :pointer
23
+ end
24
+
13
25
  # :nodoc:
14
26
  class FDSet < ::FFI::Struct
15
27
  if Curl.windows?
@@ -39,5 +39,24 @@ module Ethon
39
39
 
40
40
  # :nodoc:
41
41
  MsgCode = enum(:msg_code, msg_codes)
42
+
43
+ VERSION_IPV6 = (1<<0) # IPv6-enabled
44
+ VERSION_KERBEROS4 = (1<<1) # kerberos auth is supported
45
+ VERSION_SSL = (1<<2) # SSL options are present
46
+ VERSION_LIBZ = (1<<3) # libz features are present
47
+ VERSION_NTLM = (1<<4) # NTLM auth is supported
48
+ VERSION_GSSNEGOTIATE = (1<<5) # Negotiate auth supp
49
+ VERSION_DEBUG = (1<<6) # built with debug capabilities
50
+ VERSION_ASYNCHDNS = (1<<7) # asynchronous dns resolves
51
+ VERSION_SPNEGO = (1<<8) # SPNEGO auth is supported
52
+ VERSION_LARGEFILE = (1<<9) # supports files bigger than 2GB
53
+ VERSION_IDN = (1<<10) # International Domain Names support
54
+ VERSION_SSPI = (1<<11) # SSPI is supported
55
+ VERSION_CONV = (1<<12) # character conversions supported
56
+ VERSION_CURLDEBUG = (1<<13) # debug memory tracking supported
57
+ VERSION_TLSAUTH_SRP = (1<<14) # TLS-SRP auth is supported
58
+ VERSION_NTLM_WB = (1<<15) # NTLM delegating to winbind helper
59
+ VERSION_HTTP2 = (1<<16) # HTTP2 support built
60
+ VERSION_GSSAPI = (1<<17) # GSS-API is supported
42
61
  end
43
62
  end
@@ -44,6 +44,8 @@ module Ethon
44
44
  base.attach_function :multi_setopt_off_t, :curl_multi_setopt, [:pointer, :multi_option, :int64], :multi_code
45
45
 
46
46
  base.attach_function :version, :curl_version, [], :string
47
+ base.attach_function :version_info, :curl_version_info, [], Curl::VersionInfoData.ptr
48
+
47
49
  base.attach_function :slist_append, :curl_slist_append, [:pointer, :string], :pointer
48
50
  base.attach_function :slist_free_all, :curl_slist_free_all, [:pointer], :void
49
51
  base.instance_variable_set(:@blocking, true)
@@ -1,4 +1,5 @@
1
1
  require 'ethon/easy/informations'
2
+ require 'ethon/easy/features'
2
3
  require 'ethon/easy/callbacks'
3
4
  require 'ethon/easy/options'
4
5
  require 'ethon/easy/header'
@@ -39,6 +40,7 @@ module Ethon
39
40
  include Ethon::Easy::Http
40
41
  include Ethon::Easy::Operations
41
42
  include Ethon::Easy::ResponseCallbacks
43
+ extend Ethon::Easy::Features
42
44
 
43
45
  # Returns the curl return code.
44
46
  #
@@ -0,0 +1,30 @@
1
+ module Ethon
2
+ class Easy
3
+
4
+ # This module contains class methods for feature checks
5
+ module Features
6
+ # Returns true if this curl version supports zlib.
7
+ #
8
+ # @example Return wether zlib is supported.
9
+ # Ethon::Easy.supports_zlib?
10
+ #
11
+ # @return [ Boolean ] True if supported, else false.
12
+ def supports_zlib?
13
+ !!(Curl.version_info[:features] & Curl::VERSION_LIBZ)
14
+ end
15
+
16
+ # Returns true if this curl version supports AsynchDNS.
17
+ #
18
+ # @example
19
+ # Ethon::Easy.supports_asynch_dns?
20
+ #
21
+ # @return [ Boolean ] True if supported, else false.
22
+ def supports_asynch_dns?
23
+ !!(Curl.version_info[:features] & Curl::VERSION_ASYNCHDNS)
24
+ end
25
+
26
+ alias :supports_timeout_ms? :supports_asynch_dns?
27
+
28
+ end
29
+ end
30
+ end
@@ -8,6 +8,8 @@ module Ethon
8
8
  # for more real actions like GET, HEAD, POST and PUT.
9
9
  module Actionable
10
10
 
11
+ QUERY_OPTIONS = [ :params, :body, :params_encoding ]
12
+
11
13
  # Create a new action.
12
14
  #
13
15
  # @example Create a new action.
@@ -19,7 +21,7 @@ module Ethon
19
21
  # @return [ Action ] A new action.
20
22
  def initialize(url, options)
21
23
  @url = url
22
- @options = options.dup
24
+ @options, @query_options = parse_options(options)
23
25
  end
24
26
 
25
27
  # Return the url.
@@ -42,6 +44,16 @@ module Ethon
42
44
  @options
43
45
  end
44
46
 
47
+ # Returns the query options hash.
48
+ #
49
+ # @example Return query options.
50
+ # action.query_options
51
+ #
52
+ # @return [ Hash ] The query options.
53
+ def query_options
54
+ @query_options
55
+ end
56
+
45
57
  # Return the params.
46
58
  #
47
59
  # @example Return params.
@@ -49,7 +61,7 @@ module Ethon
49
61
  #
50
62
  # @return [ Params ] The params.
51
63
  def params
52
- @params ||= Params.new(@easy, options.delete(:params))
64
+ @params ||= Params.new(@easy, query_options.fetch(:params, nil))
53
65
  end
54
66
 
55
67
  # Return the form.
@@ -59,7 +71,17 @@ module Ethon
59
71
  #
60
72
  # @return [ Form ] The form.
61
73
  def form
62
- @form ||= Form.new(@easy, options.delete(:body))
74
+ @form ||= Form.new(@easy, query_options.fetch(:body, nil))
75
+ end
76
+
77
+ # Get the requested array encoding. By default it's
78
+ # :typhoeus, but it can also be set to :rack.
79
+ #
80
+ # @example Get encoding from options
81
+ # action.params_encoding
82
+ #
83
+ def params_encoding
84
+ @params_encoding ||= query_options.fetch(:params_encoding, :typhoeus)
63
85
  end
64
86
 
65
87
  # Setup everything necessary for a proper request.
@@ -70,6 +92,7 @@ module Ethon
70
92
  # @param [ easy ] easy the easy to setup.
71
93
  def setup(easy)
72
94
  @easy = easy
95
+
73
96
  if params.empty?
74
97
  easy.url = url
75
98
  else
@@ -87,6 +110,8 @@ module Ethon
87
110
  # @param [ Easy ] easy The easy to setup.
88
111
  def set_params(easy)
89
112
  params.escape = true
113
+ params.params_encoding = params_encoding
114
+
90
115
  base_url, base_params = url.split("?")
91
116
  base_params += "&" if base_params
92
117
  easy.url = "#{base_url}?#{base_params}#{params.to_s}"
@@ -100,6 +125,21 @@ module Ethon
100
125
  # @param [ Easy ] easy The easy to setup.
101
126
  def set_form(easy)
102
127
  end
128
+
129
+ private
130
+
131
+ def parse_options(options)
132
+ query_options = {}
133
+ options = options.dup
134
+
135
+ QUERY_OPTIONS.each do |query_option|
136
+ if options.key?(query_option)
137
+ query_options[query_option] = options.delete(query_option)
138
+ end
139
+ end
140
+
141
+ return options, query_options
142
+ end
103
143
  end
104
144
  end
105
145
  end
@@ -14,6 +14,7 @@ module Ethon
14
14
  # @param [ Easy ] easy The easy to setup.
15
15
  def set_form(easy)
16
16
  easy.url ||= url
17
+ form.params_encoding = params_encoding
17
18
  if form.multipart?
18
19
  form.escape = false
19
20
  form.materialize
@@ -14,6 +14,7 @@ module Ethon
14
14
  def set_form(easy)
15
15
  easy.upload = true
16
16
  form.escape = true
17
+ form.params_encoding = params_encoding
17
18
  easy.infilesize = form.to_s.bytesize
18
19
  easy.set_read_callback(form.to_s)
19
20
  end
@@ -77,15 +77,18 @@ module Ethon
77
77
  eval %Q|def #{name}; Curl.send(:get_info_#{type}, :#{name}, handle); end|
78
78
  end
79
79
 
80
- # Returns this curl version supports zlib.
80
+ # Returns true if this curl version supports zlib.
81
81
  #
82
82
  # @example Return wether zlib is supported.
83
83
  # easy.supports_zlib?
84
84
  #
85
85
  # @return [ Boolean ] True if supported, else false.
86
+ # @deprecated Please use the static version instead
86
87
  def supports_zlib?
87
- !!(Curl.version.match(/zlib/))
88
+ Kernel.warn("Ethon: Easy#supports_zlib? is deprecated and will be removed, please use Easy#.")
89
+ Easy.supports_zlib?
88
90
  end
91
+
89
92
  end
90
93
  end
91
94
  end
@@ -8,6 +8,7 @@ module Ethon
8
8
  # :nodoc:
9
9
  def self.included(base)
10
10
  base.send(:attr_accessor, :escape)
11
+ base.send(:attr_accessor, :params_encoding)
11
12
  end
12
13
 
13
14
  # Return wether there are elements in params or not.
@@ -95,18 +96,37 @@ module Ethon
95
96
  def recursively_generate_pairs(h, prefix, pairs)
96
97
  case h
97
98
  when Hash
98
- h.each_pair do |k,v|
99
- key = prefix.nil? ? k : "#{prefix}[#{k}]"
100
- pairs_for(v, key, pairs)
101
- end
99
+ encode_hash_pairs(h, prefix, pairs)
102
100
  when Array
103
- h.each_with_index do |v, i|
104
- key = "#{prefix}[#{i}]"
105
- pairs_for(v, key, pairs)
101
+ if params_encoding == :rack
102
+ encode_rack_array_pairs(h, prefix, pairs)
103
+ else
104
+ encode_indexed_array_pairs(h, prefix, pairs)
106
105
  end
107
106
  end
108
107
  end
109
108
 
109
+ def encode_hash_pairs(h, prefix, pairs)
110
+ h.each_pair do |k,v|
111
+ key = prefix.nil? ? k : "#{prefix}[#{k}]"
112
+ pairs_for(v, key, pairs)
113
+ end
114
+ end
115
+
116
+ def encode_indexed_array_pairs(h, prefix, pairs)
117
+ h.each_with_index do |v, i|
118
+ key = "#{prefix}[#{i}]"
119
+ pairs_for(v, key, pairs)
120
+ end
121
+ end
122
+
123
+ def encode_rack_array_pairs(h, prefix, pairs)
124
+ h.each do |v|
125
+ key = "#{prefix}[]"
126
+ pairs_for(v, key, pairs)
127
+ end
128
+ end
129
+
110
130
  def pairs_for(v, key, pairs)
111
131
  case v
112
132
  when Hash, Array
@@ -1,5 +1,5 @@
1
1
  module Ethon
2
2
 
3
3
  # Ethon version.
4
- VERSION = '0.7.3'
4
+ VERSION = '0.7.4'
5
5
  end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ethon::Easy::Informations do
4
+
5
+ describe "#supports_asynch_dns?" do
6
+ it "returns boolean" do
7
+ expect([true, false].include? Ethon::Easy.supports_asynch_dns?).to be_truthy
8
+ end
9
+ end
10
+
11
+ describe "#supports_zlib?" do
12
+ it "returns boolean" do
13
+ expect([true, false].include? Ethon::Easy.supports_zlib?).to be_truthy
14
+ end
15
+ end
16
+
17
+ describe "#supports_timeout_ms?" do
18
+ it "returns boolean" do
19
+ expect([true, false].include? Ethon::Easy.supports_timeout_ms?).to be_truthy
20
+ end
21
+ end
22
+
23
+ end
@@ -5,7 +5,8 @@ describe Ethon::Easy::Http::Post do
5
5
  let(:url) { "http://localhost:3001/" }
6
6
  let(:params) { nil }
7
7
  let(:form) { nil }
8
- let(:post) { described_class.new(url, {:params => params, :body => form}) }
8
+ let(:options) { Hash.new }
9
+ let(:post) { described_class.new(url, options.merge({:params => params, :body => form})) }
9
10
 
10
11
  describe "#setup" do
11
12
  context "when nothing" do
@@ -39,6 +40,25 @@ describe Ethon::Easy::Http::Post do
39
40
  expect(easy.url).to eq("#{url}?a=1%26")
40
41
  end
41
42
 
43
+ context "with arrays" do
44
+ let(:params) { {:a => %w( foo bar )} }
45
+
46
+ context "by default" do
47
+ it "encodes them with indexes" do
48
+ post.setup(easy)
49
+ expect(easy.url).to eq("#{url}?a%5B0%5D=foo&a%5B1%5D=bar")
50
+ end
51
+ end
52
+
53
+ context "when params_encoding is :rack" do
54
+ let(:options) { {:params_encoding => :rack} }
55
+ it "encodes them without indexes" do
56
+ post.setup(easy)
57
+ expect(easy.url).to eq("#{url}?a%5B%5D=foo&a%5B%5D=bar")
58
+ end
59
+ end
60
+ end
61
+
42
62
  it "sets postfieldsize" do
43
63
  expect(easy).to receive(:postfieldsize=).with(0)
44
64
  post.setup(easy)
@@ -214,6 +234,26 @@ describe Ethon::Easy::Http::Post do
214
234
  end
215
235
  end
216
236
  end
237
+
238
+ context "when arrays" do
239
+ let(:form) { {:a => %w( foo bar )} }
240
+
241
+ context "by default" do
242
+ it "sets copypostfields with indexed, escaped representation" do
243
+ expect(easy).to receive(:copypostfields=).with('a%5B0%5D=foo&a%5B1%5D=bar')
244
+ post.setup(easy)
245
+ end
246
+ end
247
+
248
+ context "when params_encoding is :rack" do
249
+ let(:options) { {:params_encoding => :rack} }
250
+
251
+ it "sets copypostfields with non-indexed, escaped representation" do
252
+ expect(easy).to receive(:copypostfields=).with('a%5B%5D=foo&a%5B%5D=bar')
253
+ post.setup(easy)
254
+ end
255
+ end
256
+ end
217
257
  end
218
258
 
219
259
  context "when params and body" do
@@ -5,7 +5,8 @@ describe Ethon::Easy::Http::Put do
5
5
  let(:url) { "http://localhost:3001/" }
6
6
  let(:params) { nil }
7
7
  let(:form) { nil }
8
- let(:put) { described_class.new(url, {:params => params, :body => form}) }
8
+ let(:options) { Hash.new }
9
+ let(:put) { described_class.new(url, options.merge({:params => params, :body => form})) }
9
10
 
10
11
  describe "#setup" do
11
12
  context "when nothing" do
@@ -41,6 +42,25 @@ describe Ethon::Easy::Http::Put do
41
42
  expect(easy.url).to eq("#{url}?a=1%26")
42
43
  end
43
44
 
45
+ context "with arrays" do
46
+ let(:params) { {:a => %w( foo bar )} }
47
+
48
+ context "by default" do
49
+ it "encodes them with indexes" do
50
+ put.setup(easy)
51
+ expect(easy.url).to eq("#{url}?a%5B0%5D=foo&a%5B1%5D=bar")
52
+ end
53
+ end
54
+
55
+ context "when params_encoding is :rack" do
56
+ let(:options) { {:params_encoding => :rack} }
57
+ it "encodes them without indexes" do
58
+ put.setup(easy)
59
+ expect(easy.url).to eq("#{url}?a%5B%5D=foo&a%5B%5D=bar")
60
+ end
61
+ end
62
+ end
63
+
44
64
  it "sets upload" do
45
65
  expect(easy).to receive(:upload=).with(true)
46
66
  put.setup(easy)
@@ -117,6 +137,29 @@ describe Ethon::Easy::Http::Put do
117
137
  end
118
138
  end
119
139
  end
140
+
141
+ context "when arrays" do
142
+ let(:form) { {:a => %w( foo bar )} }
143
+
144
+ before do
145
+ put.setup(easy)
146
+ easy.perform
147
+ end
148
+
149
+ context "by default" do
150
+ it "submits an indexed, escaped representation" do
151
+ expect(easy.response_body).to include('"body":"a%5B0%5D=foo&a%5B1%5D=bar"')
152
+ end
153
+ end
154
+
155
+ context "when params_encoding is :rack" do
156
+ let(:options) { {:params_encoding => :rack} }
157
+
158
+ it "submits an non-indexed, escaped representation" do
159
+ expect(easy.response_body).to include('"body":"a%5B%5D=foo&a%5B%5D=bar"')
160
+ end
161
+ end
162
+ end
120
163
  end
121
164
 
122
165
  context "when params and body"
@@ -88,7 +88,10 @@ describe Ethon::Easy::Informations do
88
88
 
89
89
  describe "#supports_zlib?" do
90
90
  it "returns true" do
91
+ Kernel.should_receive(:warn) #deprecation warning
91
92
  expect(easy.supports_zlib?).to be_truthy
92
93
  end
93
94
  end
95
+
96
+
94
97
  end
@@ -104,9 +104,9 @@ describe Ethon::Easy::Options do
104
104
  end
105
105
  end
106
106
 
107
- if Ethon::Curl.version.match("c-ares")
107
+ if Ethon::Easy.supports_timeout_ms?
108
108
  context "when timeout_ms" do
109
- let(:timeout_ms) { 900 }
109
+ let(:timeout_ms) { 100 }
110
110
 
111
111
  context "when request takes longer" do
112
112
  let(:url) { "localhost:3001?delay=1" }
@@ -118,13 +118,14 @@ describe Ethon::Easy::Options do
118
118
  end
119
119
 
120
120
  context "when connecttimeout_ms" do
121
- let(:connecttimeout_ms) { 1 }
121
+ let(:connecttimeout_ms) { 100 }
122
122
 
123
123
  context "when cannot connect" do
124
124
  let(:url) { "localhost:3002" }
125
125
 
126
126
  it "times out" do
127
- expect(easy.return_code).to eq(:couldnt_connect)
127
+ # this can either lead to a timeout or couldnt connect depending on which happens first
128
+ expect([:couldnt_connect, :operation_timedout]).to include(easy.return_code)
128
129
  end
129
130
  end
130
131
  end
@@ -106,10 +106,21 @@ describe Ethon::Easy::Queryable do
106
106
  context "when params contains an array" do
107
107
  let(:hash) { {:a => 1, :b => [2, 3]} }
108
108
 
109
- it "transforms" do
110
- expect(pairs).to include([:a, 1])
111
- expect(pairs).to include(["b[0]", 2])
112
- expect(pairs).to include(["b[1]", 3])
109
+ context "by default" do
110
+ it "transforms" do
111
+ expect(pairs).to include([:a, 1])
112
+ expect(pairs).to include(["b[0]", 2])
113
+ expect(pairs).to include(["b[1]", 3])
114
+ end
115
+ end
116
+
117
+ context "when params_encoding is :rack" do
118
+ before { params.params_encoding = :rack }
119
+ it "transforms without indexes" do
120
+ expect(pairs).to include([:a, 1])
121
+ expect(pairs).to include(["b[]", 2])
122
+ expect(pairs).to include(["b[]", 3])
123
+ end
113
124
  end
114
125
  end
115
126
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ethon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hans Hasselberg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-20 00:00:00.000000000 Z
11
+ date: 2015-06-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -55,6 +55,7 @@ files:
55
55
  - lib/ethon/easy.rb
56
56
  - lib/ethon/easy/callbacks.rb
57
57
  - lib/ethon/easy/debug_info.rb
58
+ - lib/ethon/easy/features.rb
58
59
  - lib/ethon/easy/form.rb
59
60
  - lib/ethon/easy/header.rb
60
61
  - lib/ethon/easy/http.rb
@@ -103,6 +104,7 @@ files:
103
104
  - spec/ethon/curl_spec.rb
104
105
  - spec/ethon/easy/callbacks_spec.rb
105
106
  - spec/ethon/easy/debug_info_spec.rb
107
+ - spec/ethon/easy/features_spec.rb
106
108
  - spec/ethon/easy/form_spec.rb
107
109
  - spec/ethon/easy/header_spec.rb
108
110
  - spec/ethon/easy/http/custom_spec.rb
@@ -159,6 +161,7 @@ test_files:
159
161
  - spec/ethon/curl_spec.rb
160
162
  - spec/ethon/easy/callbacks_spec.rb
161
163
  - spec/ethon/easy/debug_info_spec.rb
164
+ - spec/ethon/easy/features_spec.rb
162
165
  - spec/ethon/easy/form_spec.rb
163
166
  - spec/ethon/easy/header_spec.rb
164
167
  - spec/ethon/easy/http/custom_spec.rb