http.rb 1.1.0 → 1.2.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: a5f552ac83d2afe5184c79455af215f58e18cc7e0f01e1a8bf684a877f8b9d9a
4
- data.tar.gz: 274244f8126d9dbb09b17c1a46be7a7c037ecab83ca8ae5af5bc4d7f3463c07b
3
+ metadata.gz: 448e7dce1f8dc9a0b23a659b351d10e241ccf1e3cf853663046ec4d7e6e0c8fe
4
+ data.tar.gz: 75123ecd90c4f5333b8c9a6d62435ab20b46623a5871eb8464a224a92c900ed1
5
5
  SHA512:
6
- metadata.gz: e0fdfcf607047e62db109a3ec414cebf308b270e2757d510f8f337628f0b235a947f4769a5e78a32abd137ce764f63822ca9ff26ccfc5fbc01db39ead0ef1152
7
- data.tar.gz: fb725d77aa4f4312803dadd481b62a705dd3286568469a1ae055a609a86d9991583dd69a7110864375b5835eecbba9ab06ad39ffbc4f61e428686787690908c2
6
+ metadata.gz: 7fadfa5b0e33af922edc397877c6fecdff9fd0e5fdb2c8bbb17b9aaeb33f7cddc61553129e1ae6dafc7ee7367a4e1e0a71fa380119020dafbb50e66873f2333c
7
+ data.tar.gz: d5b35c43b60b13b3e34b1b56a5d02189266401ccb3a9d63b9d87ead07330f96efb80e2577391eea8ed0ec2a734050d7b22aa0fb21e50cfe334b53ca700ede7a6
data/CHANGELOG CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  ## 20260609
4
4
 
5
+ 1.2.0: Extract request_without_body and request_with_body.
6
+
7
+ The logic for building request objects — constructing the Net::HTTP request class, encoding bodies, and assembling query strings — lived inside the define_method loops and was unreachable except through the eight named methods. Downstream gems needing a method without a named helper (notably webdav's PROPFIND) had to build raw Net::HTTP request objects and bypass that logic entirely. Those two loop bodies are now module functions, callable directly as HTTP.request_without_body(method, ...) and HTTP.request_with_body(method, ...); the named methods delegate to them and behave identically.
8
+
9
+ 1. ~ HTTP/verbs.rb: + request_without_body() and request_with_body() module functions; the WITHOUT_BODY and WITH_BODY define_method loops now delegate to them.
10
+ 2. + test/HTTP/request_without_body_test.rb
11
+ 3. + test/HTTP/request_with_body_test.rb
12
+ 4. ~ README.md: + Constructing requests for other methods section.
13
+ 5. ~ HTTP::VERSION: /1.1.0/1.2.0/
14
+ 6. ~ CHANGELOG: + 1.2.0 entry
15
+
16
+ ## 20260609
17
+
5
18
  1.1.0: Basic auth via the options hash.
6
19
 
7
20
  Until now basic authentication was only available through credentials embedded in the URI, which forced callers needing programmatic credentials (notably the webdav gem) to construct their own Net::HTTP request objects and bypass the verb methods entirely. The options hash now accepts username: and password:, extracted the same way no_redirect is, so they never leak through to Net::HTTP. This is additive: URI credentials still work as a fallback, and explicit options take precedence over them.
data/README.md CHANGED
@@ -182,6 +182,20 @@ class A
182
182
  end
183
183
  ```
184
184
 
185
+ ### Constructing requests for other methods
186
+
187
+ The named methods cover the HTTP methods with a request class in Ruby's `Net::HTTP` stdlib. For anything else — a method without a named helper, such as `PROPFIND` — the same body encoding, query string, and request handling is available directly:
188
+
189
+ ```ruby
190
+ # No body — args become a query string:
191
+ HTTP.request_without_body(:propfind, 'http://example.com/path', {depth: 1})
192
+
193
+ # With a body — string passthrough, JSON when the content type says so, form data otherwise:
194
+ HTTP.request_with_body(:propfind, 'http://example.com/path', xml, {'Content-Type' => 'application/xml'})
195
+ ```
196
+
197
+ Both take the same `(method, uri, args_or_data, headers, options, &block)` arguments as the named methods, with the method as the first argument, and the named methods delegate to them. For full control over the request object, drop down to `HTTP.request(uri, request_object, headers, options, &block)`.
198
+
185
199
  ## Allowed values for the options hash
186
200
  #### (These pass through to Net::HTTP, except for `no_redirect`, `username`, and `password`.)
187
201
 
data/lib/HTTP/VERSION.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # HTTP::VERSION
3
3
 
4
4
  module HTTP
5
- VERSION = '1.1.0'
5
+ VERSION = '1.2.0'
6
6
  end
data/lib/HTTP/verbs.rb CHANGED
@@ -13,35 +13,43 @@ module HTTP
13
13
  WITH_BODY = %i{post put patch}
14
14
  end
15
15
 
16
+ def request_without_body(method, uri, args = {}, headers = {}, options = {}, &block)
17
+ uri = uri.is_a?(URI) ? uri : URI.parse(uri)
18
+ request_uri = uri.request_uri
19
+ unless args.empty?
20
+ request_uri += '?' + args.x_www_form_urlencode
21
+ end
22
+ request_object = Net::HTTP.const_get(method.to_s.capitalize).new(request_uri)
23
+ request(uri, request_object, headers, options, &block)
24
+ end
25
+ module_function :request_without_body
26
+
27
+ def request_with_body(method, uri, data = {}, headers = {}, options = {}, &block)
28
+ uri = uri.is_a?(URI) ? uri : URI.parse(uri)
29
+ request_object = Net::HTTP.const_get(method.to_s.capitalize).new(uri.request_uri)
30
+ content_type = headers.find{|k, v| k.downcase == 'content-type'}&.last.to_s
31
+ if data.is_a?(String)
32
+ request_object.body = data
33
+ elsif content_type.start_with?('application/json')
34
+ request_object.body = JSON.dump(data)
35
+ else
36
+ request_object.form_data = data
37
+ end
38
+ request(uri, request_object, headers, options, &block)
39
+ end
40
+ module_function :request_with_body
41
+
16
42
  VERBS::WITHOUT_BODY.each do |verb|
17
43
  define_method(verb) do |uri, args = {}, headers = {}, options = {}, &block|
18
- uri = uri.is_a?(URI) ? uri : URI.parse(uri)
19
- request_uri = uri.request_uri
20
- unless args.empty?
21
- request_uri += '?' + args.x_www_form_urlencode
22
- end
23
- request_object = Net::HTTP.const_get(verb.to_s.capitalize).new(request_uri)
24
- request(uri, request_object, headers, options, &block)
44
+ request_without_body(verb, uri, args, headers, options, &block)
25
45
  end
26
-
27
46
  module_function verb
28
47
  end
29
48
 
30
49
  VERBS::WITH_BODY.each do |verb|
31
50
  define_method(verb) do |uri, data = {}, headers = {}, options = {}, &block|
32
- uri = uri.is_a?(URI) ? uri : URI.parse(uri)
33
- request_object = Net::HTTP.const_get(verb.to_s.capitalize).new(uri.request_uri)
34
- content_type = headers.find{|k, v| k.downcase == 'content-type'}&.last.to_s
35
- if data.is_a?(String)
36
- request_object.body = data
37
- elsif content_type.start_with?('application/json')
38
- request_object.body = JSON.dump(data)
39
- else
40
- request_object.form_data = data
41
- end
42
- request(uri, request_object, headers, options, &block)
51
+ request_with_body(verb, uri, data, headers, options, &block)
43
52
  end
44
-
45
53
  module_function verb
46
54
  end
47
55
  end
@@ -0,0 +1,76 @@
1
+ # test/HTTP/request_with_body_test.rb
2
+
3
+ require_relative '../helper'
4
+
5
+ describe ".request_with_body" do
6
+ let(:uri){'http://example.com/path'}
7
+ let(:parsed_uri){URI.parse(uri)}
8
+
9
+ describe "with a string body" do
10
+ let(:body){'raw body'}
11
+
12
+ before do
13
+ stub_request(:post, 'http://example.com/path').
14
+ with(body: body).
15
+ to_return(status: 200, body: '', headers: {})
16
+ end
17
+
18
+ it "passes the string through unchanged" do
19
+ request_object = Net::HTTP::Post.new(parsed_uri.request_uri)
20
+ Net::HTTP::Post.stub(:new, request_object) do
21
+ response = HTTP.request_with_body(:post, uri, body)
22
+ _(request_object.body).must_equal(body)
23
+ _(response.success?).must_equal(true)
24
+ end
25
+ end
26
+ end
27
+
28
+ describe "with a JSON content type" do
29
+ let(:data){{a: 1, b: 2}}
30
+ let(:headers){{'Content-Type' => 'application/json'}}
31
+
32
+ before do
33
+ stub_request(:post, 'http://example.com/path').
34
+ with(body: JSON.dump(data)).
35
+ to_return(status: 200, body: '', headers: {})
36
+ end
37
+
38
+ it "JSON-encodes the data" do
39
+ request_object = Net::HTTP::Post.new(parsed_uri.request_uri)
40
+ Net::HTTP::Post.stub(:new, request_object) do
41
+ response = HTTP.request_with_body(:post, uri, data, headers)
42
+ _(request_object.body).must_equal(JSON.dump(data))
43
+ _(response.success?).must_equal(true)
44
+ end
45
+ end
46
+ end
47
+
48
+ describe "with no content type" do
49
+ let(:data){{a: 1, b: 2}}
50
+
51
+ before do
52
+ stub_request(:post, 'http://example.com/path').
53
+ with(body: data.x_www_form_urlencode).
54
+ to_return(status: 200, body: '', headers: {})
55
+ end
56
+
57
+ it "form-encodes the data" do
58
+ request_object = Net::HTTP::Post.new(parsed_uri.request_uri)
59
+ Net::HTTP::Post.stub(:new, request_object) do
60
+ response = HTTP.request_with_body(:post, uri, data)
61
+ _(request_object.body).must_equal(data.x_www_form_urlencode)
62
+ _(response.success?).must_equal(true)
63
+ end
64
+ end
65
+ end
66
+
67
+ describe "delegation from the named method" do
68
+ it "is reached by HTTP.post with the verb prepended" do
69
+ received_args = nil
70
+ HTTP.stub(:request_with_body, ->(*args, &block){received_args = args; nil}) do
71
+ HTTP.post(uri, {a: 1}, {'User-Agent' => 'Minitest'}, {use_ssl: false})
72
+ end
73
+ _(received_args).must_equal([:post, uri, {a: 1}, {'User-Agent' => 'Minitest'}, {use_ssl: false}])
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,53 @@
1
+ # test/HTTP/request_without_body_test.rb
2
+
3
+ require_relative '../helper'
4
+
5
+ describe ".request_without_body" do
6
+ let(:uri){'http://example.com/path'}
7
+ let(:parsed_uri){URI.parse(uri)}
8
+
9
+ describe "without args" do
10
+ before do
11
+ stub_request(:get, 'http://example.com/path').
12
+ to_return(status: 200, body: '', headers: {})
13
+ end
14
+
15
+ it "builds the request object for the given method" do
16
+ received_arg = nil
17
+ request_object = Net::HTTP::Get.new(parsed_uri.request_uri)
18
+ Net::HTTP::Get.stub(:new, ->(arg){received_arg = arg; request_object}) do
19
+ response = HTTP.request_without_body(:get, uri)
20
+ _(received_arg).must_equal(parsed_uri.request_uri)
21
+ _(response.success?).must_equal(true)
22
+ end
23
+ end
24
+ end
25
+
26
+ describe "with args" do
27
+ before do
28
+ stub_request(:get, 'http://example.com/path?a=1&b=2').
29
+ to_return(status: 200, body: '', headers: {})
30
+ end
31
+
32
+ it "appends the encoded query string to the request uri" do
33
+ received_arg = nil
34
+ request_uri = parsed_uri.request_uri + '?a=1&b=2'
35
+ request_object = Net::HTTP::Get.new(request_uri)
36
+ Net::HTTP::Get.stub(:new, ->(arg){received_arg = arg; request_object}) do
37
+ response = HTTP.request_without_body(:get, uri, {a: 1, b: 2})
38
+ _(received_arg).must_equal(request_uri)
39
+ _(response.success?).must_equal(true)
40
+ end
41
+ end
42
+ end
43
+
44
+ describe "delegation from the named method" do
45
+ it "is reached by HTTP.get with the verb prepended" do
46
+ received_args = nil
47
+ HTTP.stub(:request_without_body, ->(*args, &block){received_args = args; nil}) do
48
+ HTTP.get(uri, {a: 1}, {'User-Agent' => 'Minitest'}, {use_ssl: false})
49
+ end
50
+ _(received_args).must_equal([:get, uri, {a: 1}, {'User-Agent' => 'Minitest'}, {use_ssl: false}])
51
+ end
52
+ end
53
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoran
@@ -113,6 +113,8 @@ files:
113
113
  - test/HTTP/patch_test.rb
114
114
  - test/HTTP/post_test.rb
115
115
  - test/HTTP/put_test.rb
116
+ - test/HTTP/request_with_body_test.rb
117
+ - test/HTTP/request_without_body_test.rb
116
118
  - test/HTTP/trace_test.rb
117
119
  - test/Net/HTTPResponse/StatusPredicates_test.rb
118
120
  - test/helper.rb