rest-client 2.0.0.rc2-x64-mingw32 → 2.0.0.rc3-x64-mingw32

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.
@@ -38,17 +38,15 @@ module RestClient
38
38
  "<RestClient::Response #{code.inspect} #{body_truncated(10).inspect}>"
39
39
  end
40
40
 
41
- def self.create(body, net_http_res, args, request)
41
+ def self.create(body, net_http_res, request)
42
42
  result = self.new(body || '')
43
43
 
44
- result.response_set_vars(net_http_res, args, request)
44
+ result.response_set_vars(net_http_res, request)
45
45
  fix_encoding(result)
46
46
 
47
47
  result
48
48
  end
49
49
 
50
- private
51
-
52
50
  def self.fix_encoding(response)
53
51
  charset = RestClient::Utils.get_encoding_from_headers(response.headers)
54
52
  encoding = nil
@@ -56,7 +54,9 @@ module RestClient
56
54
  begin
57
55
  encoding = Encoding.find(charset) if charset
58
56
  rescue ArgumentError
59
- RestClient.log << "No such encoding: #{charset.inspect}"
57
+ if RestClient.log
58
+ RestClient.log << "No such encoding: #{charset.inspect}"
59
+ end
60
60
  end
61
61
 
62
62
  return unless encoding
@@ -66,11 +66,14 @@ module RestClient
66
66
  response
67
67
  end
68
68
 
69
+ private
70
+
69
71
  def body_truncated(length)
70
- if body.length > length
71
- body[0..length] + '...'
72
+ b = body
73
+ if b.length > length
74
+ b[0..length] + '...'
72
75
  else
73
- body
76
+ b
74
77
  end
75
78
  end
76
79
  end
@@ -11,11 +11,15 @@ module RestClient
11
11
  # Strings will effectively end up using `Encoding.default_external` when
12
12
  # this method returns nil.
13
13
  #
14
- # @param headers [Hash]
14
+ # @param headers [Hash<Symbol,String>]
15
15
  #
16
16
  # @return [String, nil] encoding Return the string encoding or nil if no
17
17
  # header is found.
18
18
  #
19
+ # @example
20
+ # >> get_encoding_from_headers({:content_type => 'text/plain; charset=UTF-8'})
21
+ # => "UTF-8"
22
+ #
19
23
  def self.get_encoding_from_headers(headers)
20
24
  type_header = headers[:content_type]
21
25
  return nil unless type_header
@@ -54,7 +58,7 @@ module RestClient
54
58
  nil
55
59
  end
56
60
 
57
- # Parse a Content-type like header.
61
+ # Parse a Content-Type like header.
58
62
  #
59
63
  # Return the main content-type and a hash of options.
60
64
  #
@@ -89,5 +93,143 @@ module RestClient
89
93
 
90
94
  [key, pdict]
91
95
  end
96
+
97
+ # Serialize a ruby object into HTTP query string parameters.
98
+ #
99
+ # There is no standard for doing this, so we choose our own slightly
100
+ # idiosyncratic format. The output closely matches the format understood by
101
+ # Rails, Rack, and PHP.
102
+ #
103
+ # If you don't want handling of complex objects and only want to handle
104
+ # simple flat hashes, you may want to use `URI.encode_www_form` instead,
105
+ # which implements HTML5-compliant URL encoded form data.
106
+ #
107
+ # @param [Hash,ParamsArray] object The object to serialize
108
+ #
109
+ # @return [String] A string appropriate for use as an HTTP query string
110
+ #
111
+ # @see {flatten_params}
112
+ #
113
+ # @see URI.encode_www_form
114
+ #
115
+ # @see See also Object#to_query in ActiveSupport
116
+ # @see http://php.net/manual/en/function.http-build-query.php
117
+ # http_build_query in PHP
118
+ # @see See also Rack::Utils.build_nested_query in Rack
119
+ #
120
+ # Notable differences from the ActiveSupport implementation:
121
+ #
122
+ # - Empty hash and empty array are treated the same as nil instead of being
123
+ # omitted entirely from the output. Rather than disappearing, they will
124
+ # appear to be nil instead.
125
+ #
126
+ # It's most common to pass a Hash as the object to serialize, but you can
127
+ # also use a ParamsArray if you want to be able to pass the same key with
128
+ # multiple values and not use the rack/rails array convention.
129
+ #
130
+ # @since 2.0.0
131
+ #
132
+ # @example Simple hashes
133
+ # >> encode_query_string({foo: 123, bar: 456})
134
+ # => 'foo=123&bar=456'
135
+ #
136
+ # @example Simple arrays
137
+ # >> encode_query_string({foo: [1,2,3]})
138
+ # => 'foo[]=1&foo[]=2&foo[]=3'
139
+ #
140
+ # @example Nested hashes
141
+ # >> encode_query_string({outer: {foo: 123, bar: 456}})
142
+ # => 'outer[foo]=123&outer[bar]=456'
143
+ #
144
+ # @example Deeply nesting
145
+ # >> encode_query_string({coords: [{x: 1, y: 0}, {x: 2}, {x: 3}]})
146
+ # => 'coords[][x]=1&coords[][y]=0&coords[][x]=2&coords[][x]=3'
147
+ #
148
+ # @example Null and empty values
149
+ # >> encode_query_string({string: '', empty: nil, list: [], hash: {}})
150
+ # => 'string=&empty&list&hash'
151
+ #
152
+ # @example Nested nulls
153
+ # >> encode_query_string({foo: {string: '', empty: nil}})
154
+ # => 'foo[string]=&foo[empty]'
155
+ #
156
+ # @example Multiple fields with the same name using ParamsArray
157
+ # >> encode_query_string(RestClient::ParamsArray.new([[:foo, 1], [:foo, 2], [:foo, 3]]))
158
+ # => 'foo=1&foo=2&foo=3'
159
+ #
160
+ # @example Nested ParamsArray
161
+ # >> encode_query_string({foo: RestClient::ParamsArray.new([[:a, 1], [:a, 2]])})
162
+ # => 'foo[a]=1&foo[a]=2'
163
+ #
164
+ # >> encode_query_string(RestClient::ParamsArray.new([[:foo, {a: 1}], [:foo, {a: 2}]]))
165
+ # => 'foo[a]=1&foo[a]=2'
166
+ #
167
+ def self.encode_query_string(object)
168
+ flatten_params(object, true).map {|k, v| v.nil? ? k : "#{k}=#{v}" }.join('&')
169
+ end
170
+
171
+ # Transform deeply nested param containers into a flat array of [key,
172
+ # value] pairs.
173
+ #
174
+ # @example
175
+ # >> flatten_params({key1: {key2: 123}})
176
+ # => [["key1[key2]", 123]]
177
+ #
178
+ # @example
179
+ # >> flatten_params({key1: {key2: 123, arr: [1,2,3]}})
180
+ # => [["key1[key2]", 123], ["key1[arr][]", 1], ["key1[arr][]", 2], ["key1[arr][]", 3]]
181
+ #
182
+ # @param object [Hash, ParamsArray] The container to flatten
183
+ # @param uri_escape [Boolean] Whether to URI escape keys and values
184
+ # @param parent_key [String] Should not be passed (used for recursion)
185
+ #
186
+ def self.flatten_params(object, uri_escape=false, parent_key=nil)
187
+ unless object.is_a?(Hash) || object.is_a?(ParamsArray) ||
188
+ (parent_key && object.is_a?(Array))
189
+ raise ArgumentError.new('expected Hash or ParamsArray, got: ' + object.inspect)
190
+ end
191
+
192
+ # transform empty collections into nil, where possible
193
+ if object.empty? && parent_key
194
+ return [[parent_key, nil]]
195
+ end
196
+
197
+ # This is essentially .map(), but we need to do += for nested containers
198
+ object.reduce([]) { |result, item|
199
+ if object.is_a?(Array)
200
+ # item is already the value
201
+ k = nil
202
+ v = item
203
+ else
204
+ # item is a key, value pair
205
+ k, v = item
206
+ k = escape(k.to_s) if uri_escape
207
+ end
208
+
209
+ processed_key = parent_key ? "#{parent_key}[#{k}]" : k
210
+
211
+ case v
212
+ when Array, Hash, ParamsArray
213
+ result.concat flatten_params(v, uri_escape, processed_key)
214
+ else
215
+ v = escape(v.to_s) if uri_escape && v
216
+ result << [processed_key, v]
217
+ end
218
+ }
219
+ end
220
+
221
+ # Encode string for safe transport by URI or form encoding. This uses a CGI
222
+ # style escape, which transforms ` ` into `+` and various special
223
+ # characters into percent encoded forms.
224
+ #
225
+ # This calls URI.encode_www_form_component for the implementation. The only
226
+ # difference between this and CGI.escape is that it does not escape `*`.
227
+ # http://stackoverflow.com/questions/25085992/
228
+ #
229
+ # @see URI.encode_www_form_component
230
+ #
231
+ def self.escape(string)
232
+ URI.encode_www_form_component(string)
233
+ end
92
234
  end
93
235
  end
@@ -1,5 +1,5 @@
1
1
  module RestClient
2
- VERSION_INFO = [2, 0, 0, 'rc2'] unless defined?(self::VERSION_INFO)
2
+ VERSION_INFO = [2, 0, 0, 'rc3'] unless defined?(self::VERSION_INFO)
3
3
  VERSION = VERSION_INFO.map(&:to_s).join('.') unless defined?(self::VERSION)
4
4
 
5
5
  def self.version
data/rest-client.gemspec CHANGED
@@ -10,22 +10,22 @@ Gem::Specification.new do |s|
10
10
  s.license = 'MIT'
11
11
  s.email = 'rest.client@librelist.com'
12
12
  s.executables = ['restclient']
13
- s.extra_rdoc_files = ['README.rdoc', 'history.md']
13
+ s.extra_rdoc_files = ['README.md', 'history.md']
14
14
  s.files = `git ls-files -z`.split("\0")
15
15
  s.test_files = `git ls-files -z spec/`.split("\0")
16
16
  s.homepage = 'https://github.com/rest-client/rest-client'
17
17
  s.summary = 'Simple HTTP and REST client for Ruby, inspired by microframework syntax for specifying actions.'
18
18
 
19
- s.add_development_dependency('webmock', '~> 1.4')
20
- s.add_development_dependency('rspec', '~> 2.99')
19
+ s.add_development_dependency('webmock', '~> 2.0')
20
+ s.add_development_dependency('rspec', '~> 3.0')
21
21
  s.add_development_dependency('pry', '~> 0')
22
22
  s.add_development_dependency('pry-doc', '~> 0')
23
23
  s.add_development_dependency('rdoc', '>= 2.4.2', '< 5.0')
24
24
  s.add_development_dependency('rubocop', '~> 0')
25
25
 
26
26
  s.add_dependency('http-cookie', '>= 1.0.2', '< 2.0')
27
- s.add_dependency('mime-types', '>= 1.16', '< 3.0')
27
+ s.add_dependency('mime-types', '>= 1.16', '< 4.0')
28
28
  s.add_dependency('netrc', '~> 0.8')
29
29
 
30
- s.required_ruby_version = '>= 1.9.3'
30
+ s.required_ruby_version = '>= 2.0.0'
31
31
  end
data/spec/helpers.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'uri'
2
+
1
3
  module Helpers
2
4
  def response_double(opts={})
3
5
  double('response', {:to_hash => {}}.merge(opts))
@@ -11,4 +13,10 @@ module Helpers
11
13
  ensure
12
14
  $stderr = original_stderr
13
15
  end
16
+
17
+ def request_double(url: 'http://example.com', method: 'get')
18
+ double('request', url: url, uri: URI.parse(url), method: method,
19
+ user: nil, password: nil, cookie_jar: HTTP::CookieJar.new,
20
+ redirection_history: nil, args: {url: url, method: method})
21
+ end
14
22
  end
@@ -41,22 +41,22 @@ describe RestClient::Request do
41
41
  describe '.execute' do
42
42
  it 'sends a user agent' do
43
43
  data = execute_httpbin_json('user-agent', method: :get)
44
- data['user-agent'].should match(/rest-client/)
44
+ expect(data['user-agent']).to match(/rest-client/)
45
45
  end
46
46
 
47
47
  it 'receives cookies on 302' do
48
48
  expect {
49
49
  execute_httpbin('cookies/set?foo=bar', method: :get, max_redirects: 0)
50
50
  }.to raise_error(RestClient::Found) { |ex|
51
- ex.http_code.should eq 302
52
- ex.response.cookies['foo'].should eq 'bar'
51
+ expect(ex.http_code).to eq 302
52
+ expect(ex.response.cookies['foo']).to eq 'bar'
53
53
  }
54
54
  end
55
55
 
56
56
  it 'passes along cookies through 302' do
57
57
  data = execute_httpbin_json('cookies/set?foo=bar', method: :get)
58
- data.should have_key('cookies')
59
- data['cookies']['foo'].should eq 'bar'
58
+ expect(data).to have_key('cookies')
59
+ expect(data['cookies']['foo']).to eq 'bar'
60
60
  end
61
61
 
62
62
  it 'handles quote wrapped cookies' do
@@ -64,8 +64,8 @@ describe RestClient::Request do
64
64
  execute_httpbin('cookies/set?foo=' + CGI.escape('"bar:baz"'),
65
65
  method: :get, max_redirects: 0)
66
66
  }.to raise_error(RestClient::Found) { |ex|
67
- ex.http_code.should eq 302
68
- ex.response.cookies['foo'].should eq '"bar:baz"'
67
+ expect(ex.http_code).to eq 302
68
+ expect(ex.response.cookies['foo']).to eq '"bar:baz"'
69
69
  }
70
70
  end
71
71
  end
@@ -8,15 +8,15 @@ describe RestClient do
8
8
  body = 'abc'
9
9
  stub_request(:get, "www.example.com").to_return(:body => body, :status => 200)
10
10
  response = RestClient.get "www.example.com"
11
- response.code.should eq 200
12
- response.body.should eq body
11
+ expect(response.code).to eq 200
12
+ expect(response.body).to eq body
13
13
  end
14
14
 
15
15
  it "a simple request with gzipped content" do
16
16
  stub_request(:get, "www.example.com").with(:headers => { 'Accept-Encoding' => 'gzip, deflate' }).to_return(:body => "\037\213\b\b\006'\252H\000\003t\000\313T\317UH\257\312,HM\341\002\000G\242(\r\v\000\000\000", :status => 200, :headers => { 'Content-Encoding' => 'gzip' } )
17
17
  response = RestClient.get "www.example.com"
18
- response.code.should eq 200
19
- response.body.should eq "i'm gziped\n"
18
+ expect(response.code).to eq 200
19
+ expect(response.body).to eq "i'm gziped\n"
20
20
  end
21
21
 
22
22
  it "a 404" do
@@ -26,10 +26,10 @@ describe RestClient do
26
26
  RestClient.get "www.example.com"
27
27
  raise
28
28
  rescue RestClient::ResourceNotFound => e
29
- e.http_code.should eq 404
30
- e.response.code.should eq 404
31
- e.response.body.should eq body
32
- e.http_body.should eq body
29
+ expect(e.http_code).to eq 404
30
+ expect(e.response.code).to eq 404
31
+ expect(e.response.body).to eq body
32
+ expect(e.http_body).to eq body
33
33
  end
34
34
  end
35
35
 
@@ -41,8 +41,8 @@ describe RestClient do
41
41
  'Content-Type' => 'text/plain; charset=UTF-8'
42
42
  })
43
43
  response = RestClient.get "www.example.com"
44
- response.encoding.should eq Encoding::UTF_8
45
- response.valid_encoding?.should eq true
44
+ expect(response.encoding).to eq Encoding::UTF_8
45
+ expect(response.valid_encoding?).to eq true
46
46
  end
47
47
 
48
48
  it 'handles windows-1252' do
@@ -52,9 +52,9 @@ describe RestClient do
52
52
  'Content-Type' => 'text/plain; charset=windows-1252'
53
53
  })
54
54
  response = RestClient.get "www.example.com"
55
- response.encoding.should eq Encoding::WINDOWS_1252
56
- response.encode('utf-8').should eq "ÿ"
57
- response.valid_encoding?.should eq true
55
+ expect(response.encoding).to eq Encoding::WINDOWS_1252
56
+ expect(response.encode('utf-8')).to eq "ÿ"
57
+ expect(response.valid_encoding?).to eq true
58
58
  end
59
59
 
60
60
  it 'handles binary' do
@@ -64,28 +64,28 @@ describe RestClient do
64
64
  'Content-Type' => 'application/octet-stream; charset=binary'
65
65
  })
66
66
  response = RestClient.get "www.example.com"
67
- response.encoding.should eq Encoding::BINARY
68
- lambda {
67
+ expect(response.encoding).to eq Encoding::BINARY
68
+ expect {
69
69
  response.encode('utf-8')
70
- }.should raise_error(Encoding::UndefinedConversionError)
71
- response.valid_encoding?.should eq true
70
+ }.to raise_error(Encoding::UndefinedConversionError)
71
+ expect(response.valid_encoding?).to eq true
72
72
  end
73
73
 
74
74
  it 'handles euc-jp' do
75
75
  body = "\xA4\xA2\xA4\xA4\xA4\xA6\xA4\xA8\xA4\xAA".
76
76
  force_encoding(Encoding::BINARY)
77
77
  body_utf8 = 'あいうえお'
78
- body_utf8.encoding.should eq Encoding::UTF_8
78
+ expect(body_utf8.encoding).to eq Encoding::UTF_8
79
79
 
80
80
  stub_request(:get, 'www.example.com').to_return(
81
81
  :body => body, :status => 200, :headers => {
82
82
  'Content-Type' => 'text/plain; charset=EUC-JP'
83
83
  })
84
84
  response = RestClient.get 'www.example.com'
85
- response.encoding.should eq Encoding::EUC_JP
86
- response.valid_encoding?.should eq true
87
- response.length.should eq 5
88
- response.encode('utf-8').should eq body_utf8
85
+ expect(response.encoding).to eq Encoding::EUC_JP
86
+ expect(response.valid_encoding?).to eq true
87
+ expect(response.length).to eq 5
88
+ expect(response.encode('utf-8')).to eq body_utf8
89
89
  end
90
90
 
91
91
  it 'defaults to Encoding.default_external' do
@@ -95,7 +95,17 @@ describe RestClient do
95
95
  })
96
96
 
97
97
  response = RestClient.get 'www.example.com'
98
- response.encoding.should eq Encoding.default_external
98
+ expect(response.encoding).to eq Encoding.default_external
99
+ end
100
+
101
+ it 'handles invalid encoding' do
102
+ stub_request(:get, 'www.example.com').to_return(
103
+ body: 'abc', status: 200, headers: {
104
+ 'Content-Type' => 'text; charset=plain'
105
+ })
106
+
107
+ response = RestClient.get 'www.example.com'
108
+ expect(response.encoding).to eq Encoding.default_external
99
109
  end
100
110
 
101
111
  it 'leaves images as binary' do
@@ -107,7 +117,7 @@ describe RestClient do
107
117
  })
108
118
 
109
119
  response = RestClient.get 'www.example.com'
110
- response.encoding.should eq Encoding::BINARY
120
+ expect(response.encoding).to eq Encoding::BINARY
111
121
  end
112
122
  end
113
123
  end
@@ -75,7 +75,7 @@ describe RestClient::Request do
75
75
  },
76
76
  )
77
77
  expect {request.execute }.to_not raise_error
78
- ran_callback.should eq(true)
78
+ expect(ran_callback).to eq(true)
79
79
  end
80
80
 
81
81
  it "fails verification when the callback returns false",
data/spec/spec_helper.rb CHANGED
@@ -5,7 +5,7 @@ require_relative './helpers'
5
5
 
6
6
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
7
  RSpec.configure do |config|
8
- config.treat_symbols_as_metadata_keys_with_true_values = true
8
+ config.raise_errors_for_deprecations!
9
9
 
10
10
  # Run specs in random order to surface order dependencies. If you find an
11
11
  # order dependency and want to debug it, you can fix the order by providing
@@ -13,6 +13,10 @@ RSpec.configure do |config|
13
13
  # --seed 1234
14
14
  config.order = 'random'
15
15
 
16
+ # always run with ruby warnings enabled
17
+ # TODO: figure out why this is so obscenely noisy (rspec bug?)
18
+ # config.warnings = true
19
+
16
20
  # add helpers
17
21
  config.include Helpers, :include_helpers
18
22
 
@@ -20,3 +24,6 @@ RSpec.configure do |config|
20
24
  mocks.yield_receiver_to_any_instance_implementation_blocks = true
21
25
  end
22
26
  end
27
+
28
+ # always run with ruby warnings enabled (see above)
29
+ $VERBOSE = true