excon 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of excon might be problematic. Click here for more details.

data/Gemfile CHANGED
@@ -2,7 +2,7 @@ source "http://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'jruby-openssl', '< 0.7.4', :platform => :jruby
5
+ gem 'jruby-openssl', :platform => :jruby
6
6
 
7
7
  group :benchmark do
8
8
  gem 'em-http-request'
data/README.md CHANGED
@@ -62,16 +62,37 @@ If you need to accept as response one or more HTTP status codes you can declare
62
62
 
63
63
  connection.request(expects => [200, 201], :method => :get, :path => path, :query => {})
64
64
 
65
+ Chunked Requests
66
+ ----------------
67
+
68
+ You can make `Transfer-Encoding: chunked` requests by passing a block that will deliver chunks, delivering an empty chunk to signal completion.
69
+
70
+ file = File.open('data')
71
+
72
+ chunker = lambda do
73
+ # Excon::CHUNK_SIZE defaults to 1048576, ie 1MB
74
+ # to_s will convert the nil receieved after everything is read to the final empty chunk
75
+ file.read(Excon::CHUNK_SIZE).to_s
76
+ end
77
+
78
+ Excon.post('http://geemus.com', :request_block => chunker)
79
+
80
+ file.close
81
+
82
+ Iterating in this way allows you to have more granular control over writes and to write things where you can not calculate the overall length up front.
83
+
65
84
  Streaming Responses
66
85
  -------------------
67
86
 
68
87
  You can stream responses by passing a block that will receive each chunk.
69
88
 
70
- Excon.get('http://geemus.com') do |chunk, remaining_bytes, total_bytes|
89
+ streamer = lambda do |chunk, remaining_bytes, total_bytes|
71
90
  puts chunk
72
91
  puts "Remaining: #{remaining_bytes.to_f / total_bytes}%"
73
92
  end
74
93
 
94
+ Excon.get('http://geemus.com', :response_block => streamer)
95
+
75
96
  Iterating over each chunk will allow you to do work on the response incrementally without buffering the entire response first. For very large responses this can lead to significant memory savings.
76
97
 
77
98
  Proxy Support
data/changelog.txt CHANGED
@@ -1,3 +1,10 @@
1
+ 0.11.0 03/15/12
2
+ ===============
3
+
4
+ * add request_block to support chunked requests
5
+ * deprecate implicit block in favor of explicit response_block
6
+ * loosen activesupport and jruby-openssl development dependencies
7
+
1
8
  0.10.1 03/13/12
2
9
  ===============
3
10
 
data/excon.gemspec CHANGED
@@ -13,8 +13,8 @@ Gem::Specification.new do |s|
13
13
  ## If your rubyforge_project name is different, then edit it and comment out
14
14
  ## the sub! line in the Rakefile
15
15
  s.name = 'excon'
16
- s.version = '0.10.1'
17
- s.date = '2012-03-13'
16
+ s.version = '0.11.0'
17
+ s.date = '2012-03-15'
18
18
  s.rubyforge_project = 'excon'
19
19
 
20
20
  ## Make sure your summary is short. The description may be as long
@@ -53,7 +53,7 @@ Gem::Specification.new do |s|
53
53
  ## List your development dependencies here. Development dependencies are
54
54
  ## those that are only needed during development
55
55
  # s.add_development_dependency('DEVDEPNAME', [">= 1.1.0", "< 2.0.0"])
56
- s.add_development_dependency('activesupport', '~>3.1.3')
56
+ s.add_development_dependency('activesupport')
57
57
  s.add_development_dependency('delorean')
58
58
  s.add_development_dependency('open4')
59
59
  s.add_development_dependency('rake')
@@ -103,6 +103,7 @@ Gem::Specification.new do |s|
103
103
  tests/instrumentation_tests.rb
104
104
  tests/proxy_tests.rb
105
105
  tests/query_string_tests.rb
106
+ tests/rackups/basic.rb
106
107
  tests/rackups/basic.ru
107
108
  tests/rackups/basic_auth.ru
108
109
  tests/rackups/proxy.ru
@@ -79,6 +79,11 @@ module Excon
79
79
  params[:path].insert(0, '/')
80
80
  end
81
81
 
82
+ if block_given?
83
+ puts("Excon requests with a block are deprecated, pass :response_block instead (#{caller.first})")
84
+ params[:response_block] = Proc.new
85
+ end
86
+
82
87
  if params.has_key?(:instrumentor)
83
88
  if (retries_remaining ||= params[:retry_limit]) < params[:retry_limit]
84
89
  event_name = "#{params[:instrumentor_name]}.retry"
@@ -86,10 +91,10 @@ module Excon
86
91
  event_name = "#{params[:instrumentor_name]}.request"
87
92
  end
88
93
  params[:instrumentor].instrument(event_name, params) do
89
- request_kernel(params, &block)
94
+ request_kernel(params)
90
95
  end
91
96
  else
92
- request_kernel(params, &block)
97
+ request_kernel(params)
93
98
  end
94
99
  rescue => request_error
95
100
  if params[:idempotent] && [Excon::Errors::SocketError,
@@ -140,10 +145,10 @@ module Excon
140
145
 
141
146
  private
142
147
 
143
- def request_kernel(params, &block)
148
+ def request_kernel(params)
144
149
  begin
145
150
  response = if params[:mock]
146
- invoke_stub(params, &block)
151
+ invoke_stub(params)
147
152
  else
148
153
  socket.params = params
149
154
  # start with "METHOD /path"
@@ -174,23 +179,22 @@ module Excon
174
179
  # finish first line with "HTTP/1.1\r\n"
175
180
  request << HTTP_1_1
176
181
 
177
- # calculate content length and set to handle non-ascii
178
- unless params[:headers].has_key?('Content-Length')
182
+ if params.has_key?(:request_block)
183
+ params[:headers]['Transfer-Encoding'] = 'chunked'
184
+ elsif ! (params[:method].to_s.casecmp('GET') == 0 && params[:body].nil?)
179
185
  # The HTTP spec isn't clear on it, but specifically, GET requests don't usually send bodies;
180
186
  # if they don't, sending Content-Length:0 can cause issues.
181
- unless (params[:method].to_s.casecmp('GET') == 0 && params[:body].nil?)
182
- params[:headers]['Content-Length'] = case params[:body]
183
- when File
184
- params[:body].binmode
185
- File.size(params[:body])
186
- when String
187
- if FORCE_ENC
188
- params[:body].force_encoding('BINARY')
189
- end
190
- params[:body].length
191
- else
192
- 0
187
+ params[:headers]['Content-Length'] = case params[:body]
188
+ when File
189
+ params[:body].binmode
190
+ File.size(params[:body])
191
+ when String
192
+ if FORCE_ENC
193
+ params[:body].force_encoding('BINARY')
193
194
  end
195
+ params[:body].length
196
+ else
197
+ 0
194
198
  end
195
199
  end
196
200
 
@@ -208,7 +212,20 @@ module Excon
208
212
  socket.write(request)
209
213
 
210
214
  # write out the body
211
- unless params[:body].nil?
215
+ if params.has_key?(:request_block)
216
+ while true
217
+ chunk = params[:request_block].call
218
+ if FORCE_ENC
219
+ chunk.force_encoding('BINARY')
220
+ end
221
+ if chunk.length > 0
222
+ socket.write(chunk.length.to_s(16) << CR_NL << chunk << CR_NL)
223
+ else
224
+ socket.write('0' << CR_NL << CR_NL)
225
+ break
226
+ end
227
+ end
228
+ elsif !params[:body].nil?
212
229
  if params[:body].is_a?(String)
213
230
  unless params[:body].empty?
214
231
  socket.write(params[:body])
@@ -221,7 +238,7 @@ module Excon
221
238
  end
222
239
 
223
240
  # read the response
224
- response = Excon::Response.parse(socket, params, &block)
241
+ response = Excon::Response.parse(socket, params)
225
242
 
226
243
  if response.headers['Connection'] == 'close'
227
244
  reset
@@ -245,7 +262,6 @@ module Excon
245
262
  end
246
263
 
247
264
  def invoke_stub(params)
248
- block_given = block_given?
249
265
  params[:captures] = {:headers => {}} # setup data to hold captures
250
266
  for stub, response in Excon.stubs
251
267
  headers_match = !stub.has_key?(:headers) || stub[:headers].keys.all? do |key|
@@ -278,17 +294,14 @@ module Excon
278
294
  response
279
295
  end
280
296
 
281
- # don't pass stuff into a block if there was an error
282
297
  if params[:expects] && ![*params[:expects]].include?(response_attributes[:status])
283
- block_given = false
284
- end
285
-
286
- if block_given && response_attributes.has_key?(:body)
298
+ # don't pass stuff into a block if there was an error
299
+ elsif params.has_key?(:response_block) && response_attributes.has_key?(:body)
287
300
  body = response_attributes.delete(:body)
288
301
  content_length = remaining = body.bytesize
289
302
  i = 0
290
303
  while i < body.length
291
- yield(body[i, CHUNK_SIZE], [remaining - CHUNK_SIZE, 0].max, content_length)
304
+ params[:response_block].call(body[i, CHUNK_SIZE], [remaining - CHUNK_SIZE, 0].max, content_length)
292
305
  remaining -= CHUNK_SIZE
293
306
  i += CHUNK_SIZE
294
307
  end
@@ -1,6 +1,6 @@
1
1
  module Excon
2
2
  unless const_defined?(:VERSION)
3
- VERSION = '0.10.1'
3
+ VERSION = '0.11.0'
4
4
  end
5
5
 
6
6
  unless const_defined?(:CHUNK_SIZE)
@@ -19,7 +19,6 @@ module Excon
19
19
 
20
20
  def self.parse(socket, params={})
21
21
  response = new(:status => socket.readline[9, 11].to_i)
22
- block_given = block_given?
23
22
 
24
23
  until ((data = socket.readline).chop!).empty?
25
24
  key, value = data.split(/:\s*/, 2)
@@ -33,30 +32,29 @@ module Excon
33
32
 
34
33
  unless (params[:method].to_s.casecmp('HEAD') == 0) || NO_ENTITY.include?(response.status)
35
34
 
36
- # don't pass stuff into a block if there was an error
37
- if params[:expects] && ![*params[:expects]].include?(response.status)
38
- block_given = false
39
- end
35
+ # check to see if expects was set and matched
36
+ expected_status = !params.has_key?(:expects) || [*params[:expects]].include?(response.status)
40
37
 
41
- if block_given
38
+ # if expects matched and there is a block, use it
39
+ if expected_status && params.has_key?(:response_block)
42
40
  if transfer_encoding_chunked
43
41
  # 2 == "/r/n".length
44
42
  while (chunk_size = socket.readline.chop!.to_i(16)) > 0
45
- yield(socket.read(chunk_size + 2).chop!, nil, nil)
43
+ params[:response_block].call(socket.read(chunk_size + 2).chop!, nil, nil)
46
44
  end
47
45
  socket.read(2)
48
46
  elsif remaining = content_length
49
47
  remaining = content_length
50
48
  while remaining > 0
51
- yield(socket.read([CHUNK_SIZE, remaining].min), [remaining - CHUNK_SIZE, 0].max, content_length)
49
+ params[:response_block].call(socket.read([CHUNK_SIZE, remaining].min), [remaining - CHUNK_SIZE, 0].max, content_length)
52
50
  remaining -= CHUNK_SIZE
53
51
  end
54
52
  else
55
53
  while remaining = socket.read(CHUNK_SIZE)
56
- yield(remaining, remaining.length, content_length)
54
+ params[:response_block].call(remaining, remaining.length, content_length)
57
55
  end
58
56
  end
59
- else
57
+ else # no block or unexpected status
60
58
  if transfer_encoding_chunked
61
59
  while (chunk_size = socket.readline.chop!.to_i(16)) > 0
62
60
  response.body << socket.read(chunk_size + 2).chop! # 2 == "/r/n".length
data/tests/bad_tests.rb CHANGED
@@ -18,9 +18,9 @@ Shindo.tests('Excon bad server interaction') do
18
18
  connection = Excon.new('http://127.0.0.1:9292')
19
19
 
20
20
  body = ""
21
- block = lambda {|chunk, remaining, total| body << chunk }
21
+ response_block = lambda {|chunk, remaining, total| body << chunk }
22
22
 
23
- connection.request(:method => :get, :path => '/eof/no_content_length_and_no_chunking', &block)
23
+ connection.request(:method => :get, :path => '/eof/no_content_length_and_no_chunking', :response_block => response_block)
24
24
 
25
25
  body
26
26
  end
@@ -0,0 +1,16 @@
1
+ require 'sinatra'
2
+
3
+ class Basic < Sinatra::Base
4
+ get('/content-length/:value') do |value|
5
+ headers("Custom" => "Foo: bar")
6
+ 'x' * value.to_i
7
+ end
8
+
9
+ post('/body-sink') do
10
+ request.body.read.size.to_s
11
+ end
12
+
13
+ post('/echo') do
14
+ request.body.read
15
+ end
16
+ end
@@ -1,14 +1,3 @@
1
- require 'sinatra'
1
+ require File.join(File.dirname(__FILE__), 'basic')
2
2
 
3
- class App < Sinatra::Base
4
- get('/content-length/:value') do |value|
5
- headers("Custom" => "Foo: bar")
6
- 'x' * value.to_i
7
- end
8
-
9
- post('/body-sink') do
10
- request.body.read.size.to_s
11
- end
12
- end
13
-
14
- run App
3
+ run Basic
@@ -1,6 +1,6 @@
1
- require 'sinatra'
1
+ require File.join(File.dirname(__FILE__), 'basic')
2
2
 
3
- class App < Sinatra::Base
3
+ class BasicAuth < Basic
4
4
  before do
5
5
  auth ||= Rack::Auth::Basic::Request.new(request.env)
6
6
  user, pass = auth.provided? && auth.basic? && auth.credentials
@@ -9,15 +9,6 @@ class App < Sinatra::Base
9
9
  throw(:halt, [401, "Not authorized\n"])
10
10
  end
11
11
  end
12
-
13
- get('/content-length/:value') do |value|
14
- headers("Custom" => "Foo: bar")
15
- 'x' * value.to_i
16
- end
17
-
18
- post('/body-sink') do
19
- request.body.read.size.to_s
20
- end
21
12
  end
22
13
 
23
- run App
14
+ run BasicAuth
data/tests/rackups/ssl.ru CHANGED
@@ -1,20 +1,10 @@
1
1
  require 'openssl'
2
- require 'sinatra'
3
2
  require 'webrick'
4
3
  require 'webrick/https'
5
4
 
6
- class App < Sinatra::Base
7
- get('/content-length/:value') do |value|
8
- headers("Custom" => "Foo: bar")
9
- 'x' * value.to_i
10
- end
5
+ require File.join(File.dirname(__FILE__), 'basic')
11
6
 
12
- post('/body-sink') do
13
- request.body.read.size.to_s
14
- end
15
- end
16
-
17
- Rack::Handler::WEBrick.run(App, {
7
+ Rack::Handler::WEBrick.run(Basic, {
18
8
  :Port => 9443,
19
9
  :SSLCertName => [["CN", WEBrick::Utils::getservername]],
20
10
  :SSLEnable => true,
data/tests/stub_tests.rb CHANGED
@@ -32,11 +32,12 @@ Shindo.tests('Excon stubs') do
32
32
  response.status
33
33
  end
34
34
 
35
- tests('request body with block given').returns('body') do
35
+ tests('request body with response_block given').returns('body') do
36
36
  body = ''
37
- connection.request(:method => :get, :path => '/content-length/100') do |chunk, remaining_bytes, total_bytes|
37
+ response_block = lambda do |chunk, remaining_bytes, total_bytes|
38
38
  body << chunk
39
39
  end
40
+ connection.request(:method => :get, :path => '/content-length/100', :response_block => response_block)
40
41
  body
41
42
  end
42
43
 
@@ -91,11 +92,12 @@ Shindo.tests('Excon stubs') do
91
92
  response.status
92
93
  end
93
94
 
94
- tests('request body with block given').returns('body') do
95
+ tests('request body with response block given').returns('body') do
95
96
  body = ''
96
- connection.request(:body => 'body', :method => :get, :path => '/content-length/100') do |chunk, remaining_bytes, total_bytes|
97
+ response_block = lambda do |chunk, remaining_bytes, total_bytes|
97
98
  body << chunk
98
99
  end
100
+ connection.request(:body => 'body', :method => :get, :path => '/content-length/100', :response_block => response_block)
99
101
  body
100
102
  end
101
103
 
@@ -114,11 +116,12 @@ Shindo.tests('Excon stubs') do
114
116
  connection = Excon.new('http://127.0.0.1:9292', :mock => true)
115
117
  Excon.stub({}, {:body => 'x' * (Excon::CHUNK_SIZE + 1)})
116
118
 
117
- test("with block") do
119
+ test("with response_block") do
118
120
  chunks = []
119
- connection.request(:method => :get, :path => '/content-length/100') do |chunk, remaining_bytes, total_bytes|
121
+ response_block = lambda do |chunk, remaining_bytes, total_bytes|
120
122
  chunks << chunk
121
123
  end
124
+ connection.request(:method => :get, :path => '/content-length/100', :response_block => response_block)
122
125
  chunks == ['x' * Excon::CHUNK_SIZE, 'x']
123
126
  end
124
127
  end
@@ -137,9 +140,10 @@ Shindo.tests('Excon stubs') do
137
140
  test("request(:expects => 200, :method => :get, :path => '/') with block does not invoke the block since it raises an error") do
138
141
  block_called = false
139
142
  begin
140
- connection.request(:expects => 200, :method => :get, :path => '/') do |_, _, _|
143
+ response_block = lambda do |_,_,_|
141
144
  block_called = true
142
145
  end
146
+ connection.request(:expects => 200, :method => :get, :path => '/', :response_block => response_block)
143
147
  rescue Excon::Errors::NotFound
144
148
  end
145
149
  !block_called
data/tests/test_helper.rb CHANGED
@@ -42,7 +42,7 @@ def basic_tests(url = 'http://127.0.0.1:9292')
42
42
  response.body
43
43
  end
44
44
 
45
- tests("block usage").returns(['x' * 100, 0, 100]) do
45
+ tests("deprecated block usage").returns(['x' * 100, 0, 100]) do
46
46
  data = []
47
47
  connection.request(:method => :get, :path => '/content-length/100') do |chunk, remaining_length, total_length|
48
48
  data = [chunk, remaining_length, total_length]
@@ -50,6 +50,15 @@ def basic_tests(url = 'http://127.0.0.1:9292')
50
50
  data
51
51
  end
52
52
 
53
+ tests("response_block usage").returns(['x' * 100, 0, 100]) do
54
+ data = []
55
+ response_block = lambda do |chunk, remaining_length, total_length|
56
+ data = [chunk, remaining_length, total_length]
57
+ end
58
+ connection.request(:method => :get, :path => '/content-length/100', :response_block => response_block)
59
+ data
60
+ end
61
+
53
62
  end
54
63
 
55
64
  tests('POST /body-sink') do
@@ -65,7 +74,24 @@ def basic_tests(url = 'http://127.0.0.1:9292')
65
74
  response = connection.request(:method => :post, :path => '/body-sink', :headers => { 'Content-Type' => 'text/plain' }, :body => '')
66
75
  response.body
67
76
  end
77
+
68
78
  end
79
+
80
+ tests('POST /echo') do
81
+
82
+ connection = Excon.new(url)
83
+
84
+ tests('request_block usage').returns('x' * 100) do
85
+ data = ['x'] * 100
86
+ request_block = lambda do
87
+ data.shift.to_s
88
+ end
89
+ response = connection.request(:method => :post, :path => '/echo', :request_block => request_block)
90
+ response.body
91
+ end
92
+
93
+ end
94
+
69
95
  end
70
96
 
71
97
  def rackup_path(*parts)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: excon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
4
+ version: 0.11.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,22 +11,22 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-03-13 00:00:00.000000000Z
14
+ date: 2012-03-15 00:00:00.000000000Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activesupport
18
- requirement: &70279372304440 !ruby/object:Gem::Requirement
18
+ requirement: &70247176859020 !ruby/object:Gem::Requirement
19
19
  none: false
20
20
  requirements:
21
- - - ~>
21
+ - - ! '>='
22
22
  - !ruby/object:Gem::Version
23
- version: 3.1.3
23
+ version: '0'
24
24
  type: :development
25
25
  prerelease: false
26
- version_requirements: *70279372304440
26
+ version_requirements: *70247176859020
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: delorean
29
- requirement: &70279372304000 !ruby/object:Gem::Requirement
29
+ requirement: &70247176858080 !ruby/object:Gem::Requirement
30
30
  none: false
31
31
  requirements:
32
32
  - - ! '>='
@@ -34,10 +34,10 @@ dependencies:
34
34
  version: '0'
35
35
  type: :development
36
36
  prerelease: false
37
- version_requirements: *70279372304000
37
+ version_requirements: *70247176858080
38
38
  - !ruby/object:Gem::Dependency
39
39
  name: open4
40
- requirement: &70279372303460 !ruby/object:Gem::Requirement
40
+ requirement: &70247176857480 !ruby/object:Gem::Requirement
41
41
  none: false
42
42
  requirements:
43
43
  - - ! '>='
@@ -45,10 +45,10 @@ dependencies:
45
45
  version: '0'
46
46
  type: :development
47
47
  prerelease: false
48
- version_requirements: *70279372303460
48
+ version_requirements: *70247176857480
49
49
  - !ruby/object:Gem::Dependency
50
50
  name: rake
51
- requirement: &70279372302840 !ruby/object:Gem::Requirement
51
+ requirement: &70247176856760 !ruby/object:Gem::Requirement
52
52
  none: false
53
53
  requirements:
54
54
  - - ! '>='
@@ -56,10 +56,10 @@ dependencies:
56
56
  version: '0'
57
57
  type: :development
58
58
  prerelease: false
59
- version_requirements: *70279372302840
59
+ version_requirements: *70247176856760
60
60
  - !ruby/object:Gem::Dependency
61
61
  name: rdoc
62
- requirement: &70279372302280 !ruby/object:Gem::Requirement
62
+ requirement: &70247176856120 !ruby/object:Gem::Requirement
63
63
  none: false
64
64
  requirements:
65
65
  - - ! '>='
@@ -67,10 +67,10 @@ dependencies:
67
67
  version: '0'
68
68
  type: :development
69
69
  prerelease: false
70
- version_requirements: *70279372302280
70
+ version_requirements: *70247176856120
71
71
  - !ruby/object:Gem::Dependency
72
72
  name: shindo
73
- requirement: &70279372301800 !ruby/object:Gem::Requirement
73
+ requirement: &70247176855480 !ruby/object:Gem::Requirement
74
74
  none: false
75
75
  requirements:
76
76
  - - ! '>='
@@ -78,10 +78,10 @@ dependencies:
78
78
  version: '0'
79
79
  type: :development
80
80
  prerelease: false
81
- version_requirements: *70279372301800
81
+ version_requirements: *70247176855480
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: sinatra
84
- requirement: &70279372301340 !ruby/object:Gem::Requirement
84
+ requirement: &70247176854820 !ruby/object:Gem::Requirement
85
85
  none: false
86
86
  requirements:
87
87
  - - ! '>='
@@ -89,7 +89,7 @@ dependencies:
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
- version_requirements: *70279372301340
92
+ version_requirements: *70247176854820
93
93
  description: EXtended http(s) CONnections
94
94
  email: geemus@gmail.com
95
95
  executables: []
@@ -134,6 +134,7 @@ files:
134
134
  - tests/instrumentation_tests.rb
135
135
  - tests/proxy_tests.rb
136
136
  - tests/query_string_tests.rb
137
+ - tests/rackups/basic.rb
137
138
  - tests/rackups/basic.ru
138
139
  - tests/rackups/basic_auth.ru
139
140
  - tests/rackups/proxy.ru
@@ -162,7 +163,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
162
163
  version: '0'
163
164
  segments:
164
165
  - 0
165
- hash: -2342946765188021843
166
+ hash: 584033928995793926
166
167
  required_rubygems_version: !ruby/object:Gem::Requirement
167
168
  none: false
168
169
  requirements: