httparty 0.21.0 → 0.23.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.
data/Gemfile CHANGED
@@ -1,6 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
  gemspec
3
3
 
4
+ gem 'base64'
4
5
  gem 'rake'
5
6
  gem 'mongrel', '1.2.0.pre2'
6
7
  gem 'json'
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![CI](https://github.com/jnunemaker/httparty/actions/workflows/ci.yml/badge.svg)](https://github.com/jnunemaker/httparty/actions/workflows/ci.yml)
4
4
 
5
- Makes http fun again! Ain't no party like a httparty, because a httparty don't stop.
5
+ Makes http fun again! Ain't no party like a httparty, because a httparty don't stop.
6
6
 
7
7
  ## Install
8
8
 
@@ -12,9 +12,8 @@ gem install httparty
12
12
 
13
13
  ## Requirements
14
14
 
15
- * Ruby 2.3.0 or higher
16
- * multi_xml
17
- * You like to party!
15
+ - Ruby 2.7.0 or higher
16
+ - You like to party!
18
17
 
19
18
  ## Examples
20
19
 
@@ -47,7 +46,8 @@ puts stack_exchange.questions
47
46
  puts stack_exchange.users
48
47
  ```
49
48
 
50
- See the [examples directory](http://github.com/jnunemaker/httparty/tree/master/examples) for even more goodies.
49
+ See the [examples directory](http://github.com/jnunemaker/httparty/tree/main/examples) for even more goodies.
50
+
51
51
  ## Command Line Interface
52
52
 
53
53
  httparty also includes the executable `httparty` which can be
@@ -63,17 +63,17 @@ httparty "https://api.stackexchange.com/2.2/questions?site=stackoverflow"
63
63
 
64
64
  ## Help and Docs
65
65
 
66
- * [Docs](https://github.com/jnunemaker/httparty/tree/master/docs)
67
- * https://github.com/jnunemaker/httparty/discussions
68
- * https://www.rubydoc.info/github/jnunemaker/httparty
66
+ - [Docs](https://github.com/jnunemaker/httparty/tree/main/docs)
67
+ - https://github.com/jnunemaker/httparty/discussions
68
+ - https://www.rubydoc.info/github/jnunemaker/httparty
69
69
 
70
70
  ## Contributing
71
71
 
72
- * Fork the project.
73
- * Run `bundle`
74
- * Run `bundle exec rake`
75
- * Make your feature addition or bug fix.
76
- * Add tests for it. This is important so I don't break it in a future version unintentionally.
77
- * Run `bundle exec rake` (No, REALLY :))
78
- * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself in another branch so I can ignore when I pull)
79
- * Send me a pull request. Bonus points for topic branches.
72
+ - Fork the project.
73
+ - Run `bundle`
74
+ - Run `bundle exec rake`
75
+ - Make your feature addition or bug fix.
76
+ - Add tests for it. This is important so I don't break it in a future version unintentionally.
77
+ - Run `bundle exec rake` (No, REALLY :))
78
+ - Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself in another branch so I can ignore when I pull)
79
+ - Send me a pull request. Bonus points for topic branches.
data/docs/README.md CHANGED
@@ -36,6 +36,8 @@ You can use this guide to work with SSL certificates.
36
36
 
37
37
  ```ruby
38
38
  # Use this example if you are using a pem file
39
+ # - cert.pem must contain the content of a PEM file having the private key appended (separated from the cert by a newline \n)
40
+ # - Use an empty string for the password if the cert is not password protected
39
41
 
40
42
  class Client
41
43
  include HTTParty
@@ -0,0 +1,90 @@
1
+ require 'httparty'
2
+
3
+ class APIClient
4
+ include HTTParty
5
+ base_uri 'api.example.com'
6
+
7
+ def self.fetch_user(id)
8
+ begin
9
+ get("/users/#{id}", foul: true)
10
+ rescue HTTParty::NetworkError => e
11
+ handle_network_error(e)
12
+ rescue HTTParty::ResponseError => e
13
+ handle_api_error(e)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def self.handle_network_error(error)
20
+ case error.cause
21
+ when Errno::ECONNREFUSED
22
+ {
23
+ error: :server_down,
24
+ message: "The API server appears to be down",
25
+ details: error.message
26
+ }
27
+ when Net::OpenTimeout, Timeout::Error
28
+ {
29
+ error: :timeout,
30
+ message: "The request timed out",
31
+ details: error.message
32
+ }
33
+ when SocketError
34
+ {
35
+ error: :network_error,
36
+ message: "Could not connect to the API server",
37
+ details: error.message
38
+ }
39
+ when OpenSSL::SSL::SSLError
40
+ {
41
+ error: :ssl_error,
42
+ message: "SSL certificate verification failed",
43
+ details: error.message
44
+ }
45
+ else
46
+ {
47
+ error: :unknown_network_error,
48
+ message: "An unexpected network error occurred",
49
+ details: error.message
50
+ }
51
+ end
52
+ end
53
+
54
+ def self.handle_api_error(error)
55
+ {
56
+ error: :api_error,
57
+ message: "API returned error #{error.response.code}",
58
+ details: error.response.body
59
+ }
60
+ end
61
+ end
62
+
63
+ # Example usage:
64
+
65
+ # 1. When server is down
66
+ result = APIClient.fetch_user(123)
67
+ puts "Server down example:"
68
+ puts result.inspect
69
+ puts
70
+
71
+ # 2. When request times out
72
+ result = APIClient.fetch_user(456)
73
+ puts "Timeout example:"
74
+ puts result.inspect
75
+ puts
76
+
77
+ # 3. When SSL error occurs
78
+ result = APIClient.fetch_user(789)
79
+ puts "SSL error example:"
80
+ puts result.inspect
81
+ puts
82
+
83
+ # 4. Simple example without a wrapper class
84
+ begin
85
+ HTTParty.get('https://api.example.com/users', foul: true)
86
+ rescue HTTParty::Foul => e
87
+ puts "Direct usage example:"
88
+ puts "Error type: #{e.cause.class}"
89
+ puts "Error message: #{e.message}"
90
+ end
data/httparty.gemspec CHANGED
@@ -13,8 +13,9 @@ Gem::Specification.new do |s|
13
13
  s.summary = 'Makes http fun! Also, makes consuming restful web services dead easy.'
14
14
  s.description = 'Makes http fun! Also, makes consuming restful web services dead easy.'
15
15
 
16
- s.required_ruby_version = '>= 2.3.0'
16
+ s.required_ruby_version = '>= 2.7.0'
17
17
 
18
+ s.add_dependency 'csv'
18
19
  s.add_dependency 'multi_xml', ">= 0.5.2"
19
20
  s.add_dependency 'mini_mime', ">= 1.0.0"
20
21
 
@@ -119,10 +119,7 @@ module HTTParty
119
119
  if add_timeout?(options[:timeout])
120
120
  http.open_timeout = options[:timeout]
121
121
  http.read_timeout = options[:timeout]
122
-
123
- from_ruby_version('2.6.0', option: :write_timeout, warn: false) do
124
- http.write_timeout = options[:timeout]
125
- end
122
+ http.write_timeout = options[:timeout]
126
123
  end
127
124
 
128
125
  if add_timeout?(options[:read_timeout])
@@ -134,15 +131,11 @@ module HTTParty
134
131
  end
135
132
 
136
133
  if add_timeout?(options[:write_timeout])
137
- from_ruby_version('2.6.0', option: :write_timeout) do
138
- http.write_timeout = options[:write_timeout]
139
- end
134
+ http.write_timeout = options[:write_timeout]
140
135
  end
141
136
 
142
137
  if add_max_retries?(options[:max_retries])
143
- from_ruby_version('2.5.0', option: :max_retries) do
144
- http.max_retries = options[:max_retries]
145
- end
138
+ http.max_retries = options[:max_retries]
146
139
  end
147
140
 
148
141
  if options[:debug_output]
@@ -157,15 +150,11 @@ module HTTParty
157
150
  #
158
151
  # @see https://bugs.ruby-lang.org/issues/6617
159
152
  if options[:local_host]
160
- from_ruby_version('2.0.0', option: :local_host) do
161
- http.local_host = options[:local_host]
162
- end
153
+ http.local_host = options[:local_host]
163
154
  end
164
155
 
165
156
  if options[:local_port]
166
- from_ruby_version('2.0.0', option: :local_port) do
167
- http.local_port = options[:local_port]
168
- end
157
+ http.local_port = options[:local_port]
169
158
  end
170
159
 
171
160
  http
@@ -173,14 +162,6 @@ module HTTParty
173
162
 
174
163
  private
175
164
 
176
- def from_ruby_version(ruby_version, option: nil, warn: true)
177
- if RUBY_VERSION >= ruby_version
178
- yield
179
- elsif warn
180
- Kernel.warn("Warning: option #{ option } requires Ruby version #{ ruby_version } or later")
181
- end
182
- end
183
-
184
165
  def add_timeout?(timeout)
185
166
  timeout && (timeout.is_a?(Integer) || timeout.is_a?(Float))
186
167
  end
@@ -1,18 +1,42 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTTParty
4
+ COMMON_NETWORK_ERRORS = [
5
+ EOFError,
6
+ Errno::ECONNABORTED,
7
+ Errno::ECONNREFUSED,
8
+ Errno::ECONNRESET,
9
+ Errno::EHOSTUNREACH,
10
+ Errno::EINVAL,
11
+ Errno::ENETUNREACH,
12
+ Errno::ENOTSOCK,
13
+ Errno::EPIPE,
14
+ Errno::ETIMEDOUT,
15
+ Net::HTTPBadResponse,
16
+ Net::HTTPHeaderSyntaxError,
17
+ Net::ProtocolError,
18
+ Net::ReadTimeout,
19
+ OpenSSL::SSL::SSLError,
20
+ SocketError,
21
+ Timeout::Error # Also covers subclasses like Net::OpenTimeout
22
+ ].freeze
23
+
4
24
  # @abstract Exceptions raised by HTTParty inherit from Error
5
25
  class Error < StandardError; end
6
26
 
27
+ # @abstract Exceptions raised by HTTParty inherit from this because it is funny
28
+ # and if you don't like fun you should be using a different library.
29
+ class Foul < Error; end
30
+
7
31
  # Exception raised when you attempt to set a non-existent format
8
- class UnsupportedFormat < Error; end
32
+ class UnsupportedFormat < Foul; end
9
33
 
10
34
  # Exception raised when using a URI scheme other than HTTP or HTTPS
11
- class UnsupportedURIScheme < Error; end
35
+ class UnsupportedURIScheme < Foul; end
12
36
 
13
37
  # @abstract Exceptions which inherit from ResponseError contain the Net::HTTP
14
38
  # response object accessible via the {#response} method.
15
- class ResponseError < Error
39
+ class ResponseError < Foul
16
40
  # Returns the response of the last request
17
41
  # @return [Net::HTTPResponse] A subclass of Net::HTTPResponse, e.g.
18
42
  # Net::HTTPOK
@@ -32,4 +56,7 @@ module HTTParty
32
56
 
33
57
  # Exception that is raised when request redirects and location header is present more than once
34
58
  class DuplicateLocationHeader < ResponseError; end
59
+
60
+ # Exception that is raised when common network errors occur.
61
+ class NetworkError < Foul; end
35
62
  end
@@ -24,6 +24,7 @@ module HTTParty
24
24
  attr_reader :request, :response
25
25
 
26
26
  def logstash_message
27
+ require 'json'
27
28
  {
28
29
  '@timestamp' => current_time,
29
30
  '@version' => 1,
@@ -29,7 +29,7 @@ module HTTParty
29
29
  @mattr_inheritable_attrs += args
30
30
 
31
31
  args.each do |arg|
32
- module_eval %(class << self; attr_accessor :#{arg} end)
32
+ singleton_class.attr_accessor(arg)
33
33
  end
34
34
 
35
35
  @mattr_inheritable_attrs
@@ -42,14 +42,12 @@ module HTTParty
42
42
  subclass.instance_variable_set(ivar, instance_variable_get(ivar).clone)
43
43
 
44
44
  if instance_variable_get(ivar).respond_to?(:merge)
45
- method = <<-EOM
45
+ subclass.class_eval <<~RUBY, __FILE__, __LINE__ + 1
46
46
  def self.#{inheritable_attribute}
47
47
  duplicate = ModuleInheritableAttributes.hash_deep_dup(#{ivar})
48
48
  #{ivar} = superclass.#{inheritable_attribute}.merge(duplicate)
49
49
  end
50
- EOM
51
-
52
- subclass.class_eval method
50
+ RUBY
53
51
  end
54
52
  end
55
53
  end
@@ -118,16 +118,19 @@ module HTTParty
118
118
  protected
119
119
 
120
120
  def xml
121
+ require 'multi_xml'
121
122
  MultiXml.parse(body)
122
123
  end
123
124
 
124
125
  UTF8_BOM = "\xEF\xBB\xBF"
125
126
 
126
127
  def json
128
+ require 'json'
127
129
  JSON.parse(body, :quirks_mode => true, :allow_nan => true)
128
130
  end
129
131
 
130
132
  def csv
133
+ require 'csv'
131
134
  CSV.parse(body)
132
135
  end
133
136
 
@@ -91,6 +91,7 @@ module HTTParty
91
91
 
92
92
  def content_type(object)
93
93
  return object.content_type if object.respond_to?(:content_type)
94
+ require 'mini_mime'
94
95
  mime = MiniMime.lookup_by_filename(object.path)
95
96
  mime ? mime.content_type : 'application/octet-stream'
96
97
  end
@@ -153,24 +153,28 @@ module HTTParty
153
153
  chunked_body = nil
154
154
  current_http = http
155
155
 
156
- self.last_response = current_http.request(@raw_request) do |http_response|
157
- if block
158
- chunks = []
159
-
160
- http_response.read_body do |fragment|
161
- encoded_fragment = encode_text(fragment, http_response['content-type'])
162
- chunks << encoded_fragment if !options[:stream_body]
163
- block.call ResponseFragment.new(encoded_fragment, http_response, current_http)
156
+ begin
157
+ self.last_response = current_http.request(@raw_request) do |http_response|
158
+ if block
159
+ chunks = []
160
+
161
+ http_response.read_body do |fragment|
162
+ encoded_fragment = encode_text(fragment, http_response['content-type'])
163
+ chunks << encoded_fragment if !options[:stream_body]
164
+ block.call ResponseFragment.new(encoded_fragment, http_response, current_http)
165
+ end
166
+
167
+ chunked_body = chunks.join
164
168
  end
165
-
166
- chunked_body = chunks.join
167
169
  end
168
- end
169
170
 
170
- handle_host_redirection if response_redirects?
171
- result = handle_unauthorized
172
- result ||= handle_response(chunked_body, &block)
173
- result
171
+ handle_host_redirection if response_redirects?
172
+ result = handle_unauthorized
173
+ result ||= handle_response(chunked_body, &block)
174
+ result
175
+ rescue *COMMON_NETWORK_ERRORS => e
176
+ raise options[:foul] ? HTTParty::NetworkError.new("#{e.class}: #{e.message}") : e
177
+ end
174
178
  end
175
179
 
176
180
  def handle_unauthorized(&block)
@@ -295,24 +299,7 @@ module HTTParty
295
299
 
296
300
  def handle_response(raw_body, &block)
297
301
  if response_redirects?
298
- options[:limit] -= 1
299
- if options[:logger]
300
- logger = HTTParty::Logger.build(options[:logger], options[:log_level], options[:log_format])
301
- logger.format(self, last_response)
302
- end
303
- self.path = last_response['location']
304
- self.redirect = true
305
- if last_response.class == Net::HTTPSeeOther
306
- unless options[:maintain_method_across_redirects] && options[:resend_on_redirect]
307
- self.http_method = Net::HTTP::Get
308
- end
309
- elsif last_response.code != '307' && last_response.code != '308'
310
- unless options[:maintain_method_across_redirects]
311
- self.http_method = Net::HTTP::Get
312
- end
313
- end
314
- capture_cookies(last_response)
315
- perform(&block)
302
+ handle_redirection(&block)
316
303
  else
317
304
  raw_body ||= last_response.body
318
305
 
@@ -331,10 +318,34 @@ module HTTParty
331
318
  end
332
319
  end
333
320
 
321
+ def handle_redirection(&block)
322
+ options[:limit] -= 1
323
+ if options[:logger]
324
+ logger = HTTParty::Logger.build(options[:logger], options[:log_level], options[:log_format])
325
+ logger.format(self, last_response)
326
+ end
327
+ self.path = last_response['location']
328
+ self.redirect = true
329
+ if last_response.class == Net::HTTPSeeOther
330
+ unless options[:maintain_method_across_redirects] && options[:resend_on_redirect]
331
+ self.http_method = Net::HTTP::Get
332
+ end
333
+ elsif last_response.code != '307' && last_response.code != '308'
334
+ unless options[:maintain_method_across_redirects]
335
+ self.http_method = Net::HTTP::Get
336
+ end
337
+ end
338
+ if http_method == Net::HTTP::Get
339
+ clear_body
340
+ end
341
+ capture_cookies(last_response)
342
+ perform(&block)
343
+ end
344
+
334
345
  def handle_host_redirection
335
346
  check_duplicate_location_header
336
347
  redirect_path = options[:uri_adapter].parse(last_response['location']).normalize
337
- return if redirect_path.relative? || path.host == redirect_path.host
348
+ return if redirect_path.relative? || path.host == redirect_path.host || uri.host == redirect_path.host
338
349
  @changed_hosts = true
339
350
  end
340
351
 
@@ -362,6 +373,14 @@ module HTTParty
362
373
  parser.call(body, format)
363
374
  end
364
375
 
376
+ # Some Web Application Firewalls reject incoming GET requests that have a body
377
+ # if we redirect, and the resulting verb is GET then we will clear the body that
378
+ # may be left behind from the initiating request
379
+ def clear_body
380
+ options[:body] = nil
381
+ @raw_request.body = nil
382
+ end
383
+
365
384
  def capture_cookies(response)
366
385
  return unless response['Set-Cookie']
367
386
  cookies_hash = HTTParty::CookieHash.new
@@ -67,12 +67,12 @@ module HTTParty
67
67
  end
68
68
 
69
69
  # Support old multiple_choice? method from pre 2.0.0 era.
70
- if ::RUBY_VERSION >= '2.0.0' && ::RUBY_PLATFORM != 'java'
70
+ if ::RUBY_PLATFORM != 'java'
71
71
  alias_method :multiple_choice?, :multiple_choices?
72
72
  end
73
73
 
74
74
  # Support old status codes method from pre 2.6.0 era.
75
- if ::RUBY_VERSION >= '2.6.0' && ::RUBY_PLATFORM != 'java'
75
+ if ::RUBY_PLATFORM != 'java'
76
76
  alias_method :gateway_time_out?, :gateway_timeout?
77
77
  alias_method :request_entity_too_large?, :payload_too_large?
78
78
  alias_method :request_time_out?, :request_timeout?
@@ -133,7 +133,7 @@ module HTTParty
133
133
  end
134
134
 
135
135
  def throw_exception
136
- if @request.options[:raise_on] && @request.options[:raise_on].include?(code)
136
+ if @request.options[:raise_on].to_a.detect { |c| code.to_s.match(/#{c.to_s}/) }
137
137
  ::Kernel.raise ::HTTParty::ResponseError.new(@response), "Code #{code} - #{body}"
138
138
  end
139
139
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTTParty
4
- VERSION = '0.21.0'
4
+ VERSION = '0.23.0'
5
5
  end
data/lib/httparty.rb CHANGED
@@ -3,11 +3,6 @@
3
3
  require 'pathname'
4
4
  require 'net/http'
5
5
  require 'uri'
6
- require 'zlib'
7
- require 'multi_xml'
8
- require 'mini_mime'
9
- require 'json'
10
- require 'csv'
11
6
 
12
7
  require 'httparty/module_inheritable_attributes'
13
8
  require 'httparty/cookie_hash'
@@ -83,7 +78,7 @@ module HTTParty
83
78
  #
84
79
  # class Foo
85
80
  # include HTTParty
86
- # raise_on [404, 500]
81
+ # raise_on [404, 500, '5[0-9]*']
87
82
  # end
88
83
  def raise_on(codes = [])
89
84
  default_options[:raise_on] = *codes
@@ -591,6 +586,13 @@ module HTTParty
591
586
  perform_request Net::HTTP::Unlock, path, options, &block
592
587
  end
593
588
 
589
+ def build_request(http_method, path, options = {})
590
+ options = ModuleInheritableAttributes.hash_deep_dup(default_options).merge(options)
591
+ HeadersProcessor.new(headers, options).call
592
+ process_cookies(options)
593
+ Request.new(http_method, path, options)
594
+ end
595
+
594
596
  attr_reader :default_options
595
597
 
596
598
  private
@@ -606,10 +608,7 @@ module HTTParty
606
608
  end
607
609
 
608
610
  def perform_request(http_method, path, options, &block) #:nodoc:
609
- options = ModuleInheritableAttributes.hash_deep_dup(default_options).merge(options)
610
- HeadersProcessor.new(headers, options).call
611
- process_cookies(options)
612
- Request.new(http_method, path, options).perform(&block)
611
+ build_request(http_method, path, options).perform(&block)
613
612
  end
614
613
 
615
614
  def process_cookies(options) #:nodoc:
@@ -676,6 +675,10 @@ module HTTParty
676
675
  def self.options(*args, &block)
677
676
  Basement.options(*args, &block)
678
677
  end
678
+
679
+ def self.build_request(*args, &block)
680
+ Basement.build_request(*args, &block)
681
+ end
679
682
  end
680
683
 
681
684
  require 'httparty/hash_conversions'
data/script/release CHANGED
@@ -18,9 +18,9 @@ gem_name=httparty
18
18
  rm -rf $gem_name-*.gem
19
19
  gem build -q $gem_name.gemspec
20
20
 
21
- # Make sure we're on the master branch.
22
- (git branch | grep -q '* master') || {
23
- echo "Only release from the master branch."
21
+ # Make sure we're on the main branch.
22
+ (git branch | grep -q '* main') || {
23
+ echo "Only release from the main branch."
24
24
  exit 1
25
25
  }
26
26
 
@@ -39,4 +39,4 @@ git fetch -t origin
39
39
 
40
40
  # Tag it and bag it.
41
41
  gem push $gem_name-*.gem && git tag "$tag" &&
42
- git push origin master && git push origin "$tag"
42
+ git push origin main && git push origin "$tag"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: httparty
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.21.0
4
+ version: 0.23.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Nunemaker
@@ -9,8 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-12-30 00:00:00.000000000 Z
12
+ date: 2025-03-27 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: csv
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
14
28
  - !ruby/object:Gem::Dependency
15
29
  name: multi_xml
16
30
  requirement: !ruby/object:Gem::Requirement
@@ -48,6 +62,7 @@ extensions: []
48
62
  extra_rdoc_files: []
49
63
  files:
50
64
  - ".editorconfig"
65
+ - ".github/dependabot.yml"
51
66
  - ".github/workflows/ci.yml"
52
67
  - ".gitignore"
53
68
  - ".rubocop.yml"
@@ -76,6 +91,7 @@ files:
76
91
  - examples/microsoft_graph.rb
77
92
  - examples/multipart.rb
78
93
  - examples/nokogiri_html_parser.rb
94
+ - examples/party_foul_mode.rb
79
95
  - examples/peer_cert.rb
80
96
  - examples/rescue_json.rb
81
97
  - examples/rubyurl.rb
@@ -123,7 +139,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
123
139
  requirements:
124
140
  - - ">="
125
141
  - !ruby/object:Gem::Version
126
- version: 2.3.0
142
+ version: 2.7.0
127
143
  required_rubygems_version: !ruby/object:Gem::Requirement
128
144
  requirements:
129
145
  - - ">="