Skip to content

Commit e924f12

Browse files
committed
Enhanced RDoc for Net::HTTPHeader
1 parent f70889c commit e924f12

File tree

1 file changed

+251
-49
lines changed

1 file changed

+251
-49
lines changed

lib/net/http/header.rb

Lines changed: 251 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,159 @@
11
# frozen_string_literal: false
2-
# The HTTPHeader module defines methods for reading and writing
3-
# HTTP headers.
42
#
5-
# It is used as a mixin by other classes, to provide hash-like
6-
# access to HTTP header values. Unlike raw hash access, HTTPHeader
7-
# provides access via case-insensitive keys. It also provides
8-
# methods for accessing commonly-used HTTP header values in more
9-
# convenient formats.
3+
# The \HTTPHeader module provides access to \HTTP headers.
4+
# The headers are a hash-like collection of key/value pairs called _fields_.
5+
#
6+
# The module is included in:
7+
#
8+
# - Net::HTTPGenericRequest (and therefore Net::HTTPRequest).
9+
# - Net::HTTPResponse.
10+
#
11+
# == About the Examples
12+
#
13+
# :include: doc/net-http/examples.rdoc
14+
#
15+
# == Fields
16+
#
17+
# A header field is a key/value pair.
18+
#
19+
# === Field Keys
20+
#
21+
# A field key may be:
22+
#
23+
# - A string: Key <tt>'Foo'</tt> is treated as if it were
24+
# <tt>'Foo'.downcase</tt>; i.e., <tt>'foo'</tt>.
25+
# - A symbol: Key <tt>:Foo</tt> is treated as if it were
26+
# <tt>:Foo.to_s.downcase</tt>; i.e., <tt>'foo'</tt>.
27+
#
28+
# Examples:
29+
#
30+
# req = Net::HTTP.get(uri)
31+
# req[:Accept] # => "*/*"
32+
# req['Accept'] # => "*/*"
33+
# req['ACCEPT'] # => "*/*"
34+
#
35+
# req['accept'] = 'text/html'
36+
# req['accept'] # => "text/html"
37+
# req[:Accept] = 'text/html'
38+
# req['accept'] # => "text/html"
39+
# req['Accept'] = 'application/json'
40+
# req['accept'] # => "application/json"
41+
# req['ACCEPT'] = 'text/plain'
42+
# req['accept'] # => "text/plain"
43+
#
44+
# === Field Values
45+
#
46+
# A field value may be returned as an array or as a string:
47+
#
48+
# - These methods return field values as arrays:
49+
#
50+
# - #get_fields: Returns the array value for the given key,
51+
# or +nil+ if it does not exist.
52+
# - #to_hash: Returns a hash of all header fields:
53+
# each key is a field name; its value is the array value for the field.
54+
#
55+
# - These methods return field values as string;
56+
# the string value for a field is equivalent to
57+
# <tt>self[key.downcase.to_s].join(', '))</tt>:
58+
#
59+
# - #[]: Returns the string value for the given key,
60+
# or +nil+ if it does not exist.
61+
# - #fetch: Like #[], but accepts a default value
62+
# to be returned if the key does not exist.
63+
#
64+
# The field value may be set:
65+
#
66+
# - #[]=: Sets the value for the given key;
67+
# the given value may be a string, a symbol, an array, or a hash.
68+
# - #add_field: Adds a given value to a value for the given key
69+
# (not overwriting the existing value).
70+
# - #delete: Deletes the field for the given key.
71+
#
72+
# Example field values:
73+
#
74+
# - \String:
75+
#
76+
# req[:foo] = 'bar'
77+
# req[:foo] # => "bar"
78+
# req.get_fields(:foo) # => ["bar"]
79+
#
80+
# - \Symbol:
81+
#
82+
# req[:foo] = :bar
83+
# req[:foo] # => "bar"
84+
# req.get_fields(:foo) # => ["bar"]
85+
#
86+
# - Simple array:
87+
#
88+
# req[:foo] = %w[bar baz bat]
89+
# req[:foo] # => "bar, baz, bat"
90+
# req.get_fields(:foo) # => ["bar", "baz", "bat"]
91+
#
92+
# - Simple hash:
93+
#
94+
# req[:foo] = {bar: 0, baz: 1, bat: 2}
95+
# req[:foo] # => "bar, 0, baz, 1, bat, 2"
96+
# req.get_fields(:foo) # => ["bar", "0", "baz", "1", "bat", "2"]
97+
#
98+
# - Nested:
99+
#
100+
# req[:foo] = [%w[bar baz], {bat: 0, bam: 1}]
101+
# req[:foo] # => "bar, baz, bat, 0, bam, 1"
102+
# req.get_fields(:foo) # => ["bar", "baz", "bat", "0", "bam", "1"]
103+
#
104+
# req[:foo] = {bar: %w[baz bat], bam: {bah: 0, bad: 1}}
105+
# req[:foo] # => "bar, baz, bat, bam, bah, 0, bad, 1"
106+
# req.get_fields(:foo) # => ["bar", "baz", "bat", "bam", "bah", "0", "bad", "1"]
107+
#
108+
# == Convenience Methods
109+
#
110+
# Various convenience methods retrieve values, set values, query values,
111+
# set form values, or iterate over fields.
112+
#
113+
# === Getters
114+
#
115+
# - #[]: Returns the string value for the given field.
116+
# - #content_length: Returns the integer value of field +:content-length+.
117+
# - #content_range: Returns the Range value of field +:content-range+.
118+
# - #content_type: Returns the string value of field +:content-type+.
119+
# - #main_type: Returns first part of the string value of field +:content-type+.
120+
# - #sub_type: Returns second part of the string value of field +:content-type+.
121+
# - #range: Returns an array of Range objects, or +nil+.
122+
# - #range_length: Returns the integer length of the range given in field +:range+.
123+
# - #type_params: Returns the string parameters for +:content-type+.
124+
#
125+
# === Setters
126+
#
127+
# - #[]=: Sets the string or array value for the given field.
128+
# - #basic_auth: Sets the string authorization header for +:Basic+ authorization.
129+
# - #content_length=: Sets the integer length for field +:content-length+.
130+
# - #content_type=: Sets the string value for field +:content-type+.
131+
# - #proxy_basic_auth: Set Proxy-Authorization: header for “Basic” authorization.
132+
# - #range=: Sets the HTTP Range: header. Accepts either a Range object as a single argument, or a beginning index and a length from that index. Example:
133+
#
134+
# === Queries
135+
#
136+
# - #chunked?: Returns whether field +:transfer-encoding+ is set to <tt>'chunked'</tt>.
137+
# - #connection_close?: Returns whether field +:connection+ is set to <tt>'close'</tt>.
138+
# - #connection_keep_alive?: Returns whether field +:connection+ is set to <tt>'keep-alive'</tt>.
139+
# - #key?: Returns whether a given field exists.
140+
#
141+
# === Form Setters
142+
#
143+
# - #set_form: Sets an HTML form data set.
144+
# - #set_form_data: Set header fields and a body from HTML form data.
145+
#
146+
# === Iterators
147+
#
148+
# - #each_capitalized: Passes each field capitalized-name/value pair to the block.
149+
# - #each_capitalized_name: Passes each capitalized field name to the block.
150+
# - #each_header: Passes each field name/value pair to the block.
151+
# - #each_name: Passes each field name to the block.
152+
# - #each_value: Passes each field value to the block.
10153
#
11154
module Net::HTTPHeader
12155

13-
def initialize_http_header(initheader)
156+
def initialize_http_header(initheader) #:nodoc:
14157
@header = {}
15158
return unless initheader
16159
initheader.each do |key, value|
@@ -33,14 +176,30 @@ def size #:nodoc: obsolete
33176

34177
alias length size #:nodoc: obsolete
35178

36-
# Returns the header field corresponding to the case-insensitive key.
37-
# For example, a key of "Content-Type" might return "text/html"
179+
# Returns the string field value for the case-insensitive field +key+,
180+
# or +nil+ if there is no such key;
181+
# see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
182+
#
183+
# req = Net::HTTP::Get.new(uri)
184+
# req[:accept] # => "*/*"
185+
# req[:foo] = %w[bar baz bat]
186+
# req[:foo] # => "bar, baz, bat"
187+
# res[:nosuch] # => nil
188+
#
38189
def [](key)
39190
a = @header[key.downcase.to_s] or return nil
40191
a.join(', ')
41192
end
42193

43-
# Sets the header field corresponding to the case-insensitive key.
194+
# Sets the value for the case-insensitive +key+ to +val+,
195+
# overwriting the previous value if the field exists;
196+
# see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
197+
#
198+
# req = Net::HTTP::Get.new(uri)
199+
# req[:accept] # => "*/*"
200+
# req[:accept] = 'text/html'
201+
# req[:accept] # => "text/html"
202+
#
44203
def []=(key, val)
45204
unless val
46205
@header.delete key.downcase.to_s
@@ -49,20 +208,18 @@ def []=(key, val)
49208
set_field(key, val)
50209
end
51210

52-
# [Ruby 1.8.3]
53-
# Adds a value to a named header field, instead of replacing its value.
54-
# Second argument +val+ must be a String.
55-
# See also #[]=, #[] and #get_fields.
211+
# Adds value +val+ to the value array for field +key+ if the field exists;
212+
# creates the field with the given +key+ and +val+ if it does not exist.
213+
# see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
56214
#
57-
# request.add_field 'X-My-Header', 'a'
58-
# p request['X-My-Header'] #=> "a"
59-
# p request.get_fields('X-My-Header') #=> ["a"]
60-
# request.add_field 'X-My-Header', 'b'
61-
# p request['X-My-Header'] #=> "a, b"
62-
# p request.get_fields('X-My-Header') #=> ["a", "b"]
63-
# request.add_field 'X-My-Header', 'c'
64-
# p request['X-My-Header'] #=> "a, b, c"
65-
# p request.get_fields('X-My-Header') #=> ["a", "b", "c"]
215+
# req = Net::HTTP::Get.new(uri)
216+
# req.add_field(:foo, 'bar')
217+
# req[:foo] # => "bar"
218+
# req.add_field(:foo, 'baz')
219+
# req[:foo] # => "bar, baz"
220+
# req.add_field(:foo, %w[baz bam])
221+
# req[:foo] # => "bar, baz, baz, bam"
222+
# req.get_fields(:foo) # => ["bar", "baz", "baz", "bam"]
66223
#
67224
def add_field(key, val)
68225
stringified_downcased_key = key.downcase.to_s
@@ -101,41 +258,63 @@ def add_field(key, val)
101258
end
102259
end
103260

104-
# [Ruby 1.8.3]
105-
# Returns an array of header field strings corresponding to the
106-
# case-insensitive +key+. This method allows you to get duplicated
107-
# header fields without any processing. See also #[].
261+
# Returns the array field value for the given +key+,
262+
# or +nil+ if there is no such field;
263+
# see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
108264
#
109-
# p response.get_fields('Set-Cookie')
110-
# #=> ["session=al98axx; expires=Fri, 31-Dec-1999 23:58:23",
111-
# "query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"]
112-
# p response['Set-Cookie']
113-
# #=> "session=al98axx; expires=Fri, 31-Dec-1999 23:58:23, query=rubyscript; expires=Fri, 31-Dec-1999 23:58:23"
265+
# req = Net::HTTP::Get.new(uri)
266+
# req[:foo] = 'bar'
267+
# req.get_fields(:foo) # => ["bar"]
268+
# req.add_field(:foo, 'baz')
269+
# req.get_fields(:foo) # => ["bar", "baz"]
270+
# req.get_fields(:nosuch) # => nil
114271
#
115272
def get_fields(key)
116273
stringified_downcased_key = key.downcase.to_s
117274
return nil unless @header[stringified_downcased_key]
118275
@header[stringified_downcased_key].dup
119276
end
120277

121-
# Returns the header field corresponding to the case-insensitive key.
122-
# Returns the default value +args+, or the result of the block, or
123-
# raises an IndexError if there's no header field named +key+
124-
# See Hash#fetch
278+
# :call-seq
279+
# fetch(key, default_val = nil) {|key| ... }
280+
#
281+
# With a block, returns the string value for +key+ if it exists;
282+
# otherwise returns the value of the block;
283+
# see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
284+
#
285+
# req = Net::HTTP::Get.new(uri)
286+
# req[:foo] = 'bar'
287+
# req.fetch(:foo) {|key| key.capitalize } # => "bar"
288+
# req.fetch(:nosuch) {|key| key.capitalize } # => "Nosuch"
289+
#
290+
# With no block, returns the string value for +key+ if it exists;
291+
# otherwise, returns +default_val+ if it was given;
292+
# otherwise raises an exception:
293+
#
294+
# req.fetch(:foo) # => "bar"
295+
# req.fetch(:nosuch, :baz) # => :baz
296+
# req.fetch(:nosuch) # Raises IndexError.
297+
#
125298
def fetch(key, *args, &block) #:yield: +key+
126299
a = @header.fetch(key.downcase.to_s, *args, &block)
127300
a.kind_of?(Array) ? a.join(', ') : a
128301
end
129302

130-
# Iterates through the header names and values, passing in the name
131-
# and value to the code block supplied.
303+
# Calls the block with each key/value pair;
304+
# returns the value of #to_hash;
305+
# see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
132306
#
133-
# Returns an enumerator if no block is given.
307+
# req = Net::HTTP::Get.new(uri)
308+
# req.each_header {|key, value| p [key, value] }
134309
#
135-
# Example:
310+
# Output:
136311
#
137-
# response.header.each_header {|key,value| puts "#{key} = #{value}" }
312+
# ["accept-encoding", "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"]
313+
# ["accept", "*/*"]
314+
# ["user-agent", "Ruby"]
315+
# ["host", "jsonplaceholder.typicode.com"]
138316
#
317+
# Returns an enumerator if no block is given.
139318
def each_header #:yield: +key+, +value+
140319
block_given? or return enum_for(__method__) { @header.size }
141320
@header.each do |k,va|
@@ -145,23 +324,46 @@ def each_header #:yield: +key+, +value+
145324

146325
alias each each_header
147326

148-
# Iterates through the header names in the header, passing
149-
# each header name to the code block.
327+
# Calls the block with each field key;
328+
# returns the value of #to_hash;
329+
# see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
330+
#
331+
# req = Net::HTTP::Get.new(uri)
332+
# req.each_key {|key| p key }
333+
#
334+
# Output:
335+
#
336+
# "accept-encoding"
337+
# "accept"
338+
# "user-agent"
339+
# "host"
150340
#
151341
# Returns an enumerator if no block is given.
342+
#
343+
# Net::HTTPHeader#each_name is an alias for Net::HTTPHeader#each_key.
152344
def each_name(&block) #:yield: +key+
153345
block_given? or return enum_for(__method__) { @header.size }
154346
@header.each_key(&block)
155347
end
156348

157349
alias each_key each_name
158350

159-
# Iterates through the header names in the header, passing
160-
# capitalized header names to the code block.
351+
# Calls the block with each capitalized field name;
352+
# returns the value of #to_hash;
353+
# see {Fields}[rdoc-ref:Net::HTTPHeader@Fields]:
161354
#
162-
# Note that header names are capitalized systematically;
163-
# capitalization may not match that used by the remote HTTP
164-
# server in its response.
355+
# req = Net::HTTP::Get.new(uri)
356+
# req.each_capitalized_name {|key| p key }
357+
#
358+
# Output:
359+
#
360+
# "Accept-Encoding"
361+
# "Accept"
362+
# "User-Agent"
363+
# "Host"
364+
#
365+
# The capitalization is system-dependent;
366+
# see {Case Mapping}[https://docs.ruby-lang.org/en/master/case_mapping_rdoc.html].
165367
#
166368
# Returns an enumerator if no block is given.
167369
def each_capitalized_name #:yield: +key+

0 commit comments

Comments
 (0)