tcp-client 0.9.0 → 0.9.4

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: 20df105b07989653ac9e9c877672318e1da4eb6a5171b088b137422ff03d22db
4
- data.tar.gz: 393c2bf3f983f1da7dc8e3517b0cd7b170c2cdede3c546b603def84512e93806
3
+ metadata.gz: 114da301d59fc9cf9c3d3bda508f4d23b5b4991877a5dc7504d4da97114f8e7f
4
+ data.tar.gz: 9d0815501de340b485cba157aff05097597948d023a7eca6c45a8ead3a4e3d0d
5
5
  SHA512:
6
- metadata.gz: c94f0a7c51cd5b33edf0de9fb02d454e539f95b79891ad81c81adb4832829059fc34b8c3d4e141594dd0b95752807f1c32dbc9c5192914a5ec02345bb056075c
7
- data.tar.gz: 1ab3ef36b1534cf697c911c5d4ce01137dc9860598daa34765521cbec48fe6698294402cf0a0b768f2c460212cb3ce9378adb12ba7e65c76f1531e7bd66a1688
6
+ metadata.gz: a560644d578cedccaf1e2665f518b3a6a4e225886cfc561a8b62087420d93b958ee4741d8efde3b456fa15ce24fd5ee2f6a1121b55855205ffae5abf17becf97
7
+ data.tar.gz: f1f0ed0b87f8ee9c9b376b6b567c45aecb204c5b3de044c97f6ba080071c3c8e70da8bca8cca2484d5ddec06df181ee4b007e9ed826045e205d77df38eefbbbd
data/.yardopts ADDED
@@ -0,0 +1,5 @@
1
+ --readme README.md
2
+ --title 'tcp-client Documentation'
3
+ --charset utf-8
4
+ --markup markdown
5
+ 'lib/**/*.rb' - 'LICENSE'
data/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  A TCP client implementation with working timeout support.
4
4
 
5
+ - Gem: [rubygems.org](https://rubygems.org/gems/tcp-client)
6
+ - Source: [github.com](https://github.com/mblumtritt/tcp-client)
7
+ - Help: [rubydoc.info](https://rubydoc.info/github/mblumtritt/tcp-client/main/index)
8
+
5
9
  ## Description
6
10
 
7
11
  This Gem implements a TCP client with (optional) SSL support. It is an easy to use, versatile configurable client that can correctly handle time limits. Unlike other implementations, this client respects predefined/configurable time limits for each method (`connect`, `read`, `write`). Deadlines for a sequence of read/write actions can also be monitored.
@@ -30,6 +34,8 @@ TCPClient.with_deadline(1.5, 'www.google.com:443', cfg) do |client|
30
34
  end
31
35
  ```
32
36
 
37
+ For more samples see [the samples dir](https://github.com/mblumtritt/tcp-client/tree/main/sample)
38
+
33
39
  ## Installation
34
40
 
35
41
  Use [Bundler](http://gembundler.com/) to use TCPClient in your own project:
data/gems.rb CHANGED
@@ -1,3 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source('https://rubygems.org') { gemspec }
3
+ source 'https://rubygems.org'
4
+ gemspec
@@ -21,24 +21,31 @@ class TCPClient
21
21
  # Initializes an address
22
22
  # @overload initialize(addr)
23
23
  # The addr can be specified as
24
- # - a valid named address containing the port like +my.host.test:80+
25
- # - a valid TCPv4 address like +142.250.181.206:80+
26
- # - a valid TCPv6 address like +[2001:16b8:5093:3500:ad77:abe6:eb88:47b6]:80+
27
24
  #
28
- # @param addr [String] address string
25
+ # - a valid named address containing the port like "my.host.test:80"
26
+ # - a valid TCPv4 address like "142.250.181.206:80"
27
+ # - a valid TCPv6 address like
28
+ # "[2001:16b8:5093:3500:ad77:abe6:eb88:47b6]:80"
29
29
  #
30
- # @overload initialize(address)
31
- # Used to create a copy
30
+ # @example create an Address instance with a host name and port
31
+ # Address.new('www.google.com:80')
32
+ #
33
+ # @param addr [String] address containing host and port name
32
34
  #
33
- # @param address [Address]
34
35
  #
35
36
  # @overload initialize(addrinfo)
36
37
  #
38
+ # @example create an Address with an Addrinfo
39
+ # Address.new(Addrinfo.tcp('www.google.com', 'http'))
40
+ #
37
41
  # @param addrinfo [Addrinfo] containing the addressed host and port
38
42
  #
39
43
  # @overload initialize(port)
40
44
  # Adresses the port on the local machine.
41
45
  #
46
+ # @example create an Address for localhost on port 80
47
+ # Address.new(80)
48
+ #
42
49
  # @param port [Integer] the addressed port
43
50
  #
44
51
  def initialize(addr)
@@ -56,18 +63,27 @@ class TCPClient
56
63
  end
57
64
 
58
65
  #
59
- # @return [String] text representation of self as "<host>:<port>"
66
+ # @attribute [r] port
67
+ # @return [Integer] the port number
68
+ #
69
+ def port
70
+ @addrinfo.ip_port
71
+ end
72
+
73
+ #
74
+ # @return [String] text representation of self as "host:port"
60
75
  #
61
76
  def to_s
62
- return "[#{@hostname}]:#{@addrinfo.ip_port}" if @hostname.index(':') # IP6
63
- "#{@hostname}:#{@addrinfo.ip_port}"
77
+ hostname.index(':') ? "[#{hostname}]:#{port}" : "#{hostname}:#{port}"
64
78
  end
65
79
 
66
80
  #
67
- # @return [Hash] containing the host and port
81
+ # Convert `self` to a Hash containing host and port attribute.
82
+ #
83
+ # @return [Hash] host and port
68
84
  #
69
85
  def to_h
70
- { host: @hostname, port: @addrinfo.ip_port }
86
+ { host: hostname, port: port }
71
87
  end
72
88
 
73
89
  # @!visibility private
@@ -89,7 +105,7 @@ class TCPClient
89
105
  end
90
106
 
91
107
  def init_from_addrinfo(addrinfo)
92
- @hostname, _port = addrinfo.getnameinfo(Socket::NI_NUMERICSERV)
108
+ @hostname = addrinfo.getnameinfo(Socket::NI_NUMERICSERV).first
93
109
  @addrinfo = addrinfo
94
110
  end
95
111
 
@@ -102,7 +118,7 @@ class TCPClient
102
118
  def from_string(str)
103
119
  idx = str.rindex(':') or return nil, str.to_i
104
120
  name = str[0, idx].delete_prefix('[').delete_suffix(']')
105
- [name, str[idx + 1, str.size - idx].to_i]
121
+ [name.empty? ? nil : name, str[idx + 1, str.size - idx].to_i]
106
122
  end
107
123
  end
108
124
  end
@@ -6,55 +6,56 @@ class TCPClient
6
6
  #
7
7
  # A Configuration is used to configure the behavior of a {TCPClient} instance.
8
8
  #
9
- # It allows to specify to monitor timeout, how to handle exceptions, if SSL
9
+ # It allows to specify the monitor timeout, how to handle exceptions, if SSL
10
10
  # should be used and to setup the underlying Socket.
11
11
  #
12
12
  class Configuration
13
13
  #
14
- # @overload create(options)
15
- # Shorthand to create a new configuration with given options.
16
- #
17
- # @example
18
- # config = TCPClient::Configuration.create(buffered: false)
19
- #
20
- # @param options [Hash] see {#initialize} for details
21
- #
22
- # @return [Configuration] the initialized configuration
23
- #
24
- # @overload create(&block)
25
- # Shorthand to initialize a new configuration.
14
+ # Shorthand to create a new configuration.
26
15
  #
16
+ # @overload create()
27
17
  # @example
28
18
  # config = TCPClient::Configuration.create do |cfg|
29
19
  # cfg.buffered = false
30
20
  # cfg.ssl_params = { min_version: :TLS1_2, max_version: :TLS1_3 }
31
21
  # end
32
22
  #
33
- # @yieldparam cfg {Configuration}
23
+ # @yieldparam configuration {Configuration}
34
24
  #
35
- # @return [Configuration] the initialized configuration
25
+ # @overload create(options)
26
+ # @example
27
+ # config = TCPClient::Configuration.create(buffered: false)
28
+ #
29
+ # @param options [Hash<Symbol,Object>] see {#initialize} for details
30
+ #
31
+ # @return [Configuration] the initialized configuration
36
32
  #
37
33
  def self.create(options = {})
38
- cfg = new(options)
39
- yield(cfg) if block_given?
40
- cfg
34
+ configuration = new(options)
35
+ yield(configuration) if block_given?
36
+ configuration
41
37
  end
42
38
 
43
39
  #
44
40
  # Intializes the instance with given options.
45
41
  #
46
- # @param options [Hash]
42
+ # @param options [Hash<Symbol,Object>]
47
43
  # @option options [Boolean] :buffered, see {#buffered}
48
44
  # @option options [Boolean] :keep_alive, see {#keep_alive}
49
45
  # @option options [Boolean] :reverse_lookup, see {#reverse_lookup}
50
- # @option options [Boolean] :normalize_network_errors, see {#normalize_network_errors}
46
+ # @option options [Hash<Symbol, Object>] :ssl_params, see {#ssl_params}
51
47
  # @option options [Numeric] :connect_timeout, see {#connect_timeout}
52
- # @option options [Exception] :connect_timeout_error, see {#connect_timeout_error}
48
+ # @option options [Class<Exception>] :connect_timeout_error, see
49
+ # {#connect_timeout_error}
53
50
  # @option options [Numeric] :read_timeout, see {#read_timeout}
54
- # @option options [Exception] :read_timeout_error, see {#read_timeout_error}
51
+ # @option options [Class<Exception>] :read_timeout_error, see
52
+ # {#read_timeout_error}
55
53
  # @option options [Numeric] :write_timeout, see {#write_timeout}
56
- # @option options [Exception] :write_timeout_error, see {#write_timeout_error}
57
- # @option options [Hash<Symbol, Object>] :ssl_params, see {#ssl_params}
54
+ # @option options [Class<Exception>] :write_timeout_error, see
55
+ # {#write_timeout_error}
56
+ # @option options [Boolean] :normalize_network_errors, see
57
+ # {#normalize_network_errors}
58
+ #
58
59
  #
59
60
  def initialize(options = {})
60
61
  @buffered = @keep_alive = @reverse_lookup = true
@@ -66,11 +67,13 @@ class TCPClient
66
67
  options.each_pair { |attribute, value| set(attribute, value) }
67
68
  end
68
69
 
70
+ # @!group Instance Attributes Socket Level
71
+
69
72
  #
70
- # Enables/disables use of Socket-level buffers.
73
+ # Enables/disables use of Socket-level buffering
71
74
  #
72
- # @return [true] if the connection is allowed to use internal buffers (default)
73
- # @return [false] if buffering is not allowed
75
+ # @return [Boolean] wheter the connection is allowed to use internal buffers
76
+ # (default) or not
74
77
  #
75
78
  attr_reader :buffered
76
79
 
@@ -81,8 +84,8 @@ class TCPClient
81
84
  #
82
85
  # Enables/disables use of Socket-level keep alive handling.
83
86
  #
84
- # @return [true] if the connection is allowed to use keep alive signals (default)
85
- # @return [false] if the connection should not check keep alive
87
+ # @return [Boolean] wheter the connection is allowed to use keep alive
88
+ # signals (default) or not
86
89
  #
87
90
  attr_reader :keep_alive
88
91
 
@@ -93,8 +96,8 @@ class TCPClient
93
96
  #
94
97
  # Enables/disables address lookup.
95
98
  #
96
- # @return [true] if the connection is allowed to lookup the address (default)
97
- # @return [false] if the address lookup is not required
99
+ # @return [Boolean] wheter the connection is allowed to lookup the address
100
+ # (default) or not
98
101
  #
99
102
  attr_reader :reverse_lookup
100
103
 
@@ -103,55 +106,45 @@ class TCPClient
103
106
  end
104
107
 
105
108
  #
106
- # Enables/disables if network exceptions should be raised as {NetworkError}.
107
- #
108
- # @return [true] if all network exceptions should be raised as {NetworkError}
109
- # @return [false] if socket/system errors should not be normalzed (default)
109
+ # @!parse attr_reader :ssl?
110
+ # @return [Boolean] wheter SSL is configured, see {#ssl_params}
110
111
  #
111
- attr_reader :normalize_network_errors
112
-
113
- def normalize_network_errors=(value)
114
- @normalize_network_errors = value ? true : false
112
+ def ssl?
113
+ @ssl_params ? true : false
115
114
  end
116
115
 
117
116
  #
118
- # @attribute [w] timeout
119
- # Shorthand to set timeout value for connect, read and write at once or to disable any timeout monitoring
117
+ # Parameters used to initialize a SSL context. SSL/TLS will only be used if
118
+ # this attribute is not `nil`.
120
119
  #
121
- # @return [Numeric] maximum time in seconds for any action
122
- # @return [nil] if all timeout monitoring should be disabled (default)
123
- #
124
- # @see #connect_timeout
125
- # @see #read_timeout
126
- # @see #write_timeout
120
+ # @return [Hash<Symbol, Object>] SSL parameters for the SSL context
121
+ # @return [nil] if no SSL should be used (default)
127
122
  #
128
- def timeout=(value)
129
- @connect_timeout = @write_timeout = @read_timeout = seconds(value)
130
- end
123
+ attr_reader :ssl_params
131
124
 
132
- #
133
- # @attribute [w] timeout_error
134
- # Shorthand to configure exception class raised when connect, read or write exceeded the configured timeout
135
- #
136
- # @return [Class] exception class raised
137
- #
138
- # @raise [NotAnExceptionError] if given argument is not an Exception class
139
- #
140
- # @see #connect_timeout_error
141
- # @see #read_timeout_error
142
- # @see #write_timeout_error
143
- #
144
- def timeout_error=(value)
145
- raise(NotAnExceptionError, value) unless exception_class?(value)
146
- @connect_timeout_error =
147
- @read_timeout_error = @write_timeout_error = value
125
+ def ssl_params=(value)
126
+ @ssl_params =
127
+ if value.respond_to?(:to_hash)
128
+ Hash[value.to_hash]
129
+ elsif value.respond_to?(:to_h)
130
+ value.nil? ? nil : Hash[value.to_h]
131
+ else
132
+ value ? {} : nil
133
+ end
148
134
  end
135
+ alias ssl= ssl_params=
136
+
137
+ # @!endgroup
138
+
139
+ # @!group Instance Attributes Timeout Monitoring
149
140
 
150
141
  #
151
- # Configures maximum time in seconds to establish a connection.
142
+ # The maximum time in seconds to establish a connection.
152
143
  #
153
- # @return [Numeric] maximum time in seconds to establish a connection
154
- # @return [nil] if the connect time should not be checked (default)
144
+ # @return [Numeric] maximum time in seconds
145
+ # @return [nil] if the connect time should not be monitored (default)
146
+ #
147
+ # @see TCPClient#connect
155
148
  #
156
149
  attr_reader :connect_timeout
157
150
 
@@ -160,7 +153,10 @@ class TCPClient
160
153
  end
161
154
 
162
155
  #
163
- # @return [Class] exception class raised if a {TCPClient#connect} timed out
156
+ # The exception class which will be raised if {TCPClient#connect} can not
157
+ # be finished in time.
158
+ #
159
+ # @return [Class<Exception>] exception class raised
164
160
  # @raise [NotAnExceptionError] if given argument is not an Exception class
165
161
  #
166
162
  attr_reader :connect_timeout_error
@@ -171,10 +167,12 @@ class TCPClient
171
167
  end
172
168
 
173
169
  #
174
- # Configures maximum time in seconds to finish a {TCPClient#read}.
170
+ # The maximum time in seconds to read from a connection.
175
171
  #
176
- # @return [Numeric] maximum time in seconds to finish a {TCPClient#read} request
177
- # @return [nil] if the read time should not be checked (default)
172
+ # @return [Numeric] maximum time in seconds
173
+ # @return [nil] if the read time should not be monitored (default)
174
+ #
175
+ # @see TCPClient#read
178
176
  #
179
177
  attr_reader :read_timeout
180
178
 
@@ -183,7 +181,10 @@ class TCPClient
183
181
  end
184
182
 
185
183
  #
186
- # @return [Class] exception class raised if a {TCPClient#read} timed out
184
+ # The exception class which will be raised if {TCPClient#read} can not be
185
+ # finished in time.
186
+ #
187
+ # @return [Class<Exception>] exception class raised
187
188
  # @raise [NotAnExceptionError] if given argument is not an Exception class
188
189
  #
189
190
  attr_reader :read_timeout_error
@@ -194,10 +195,12 @@ class TCPClient
194
195
  end
195
196
 
196
197
  #
197
- # Configures maximum time in seconds to finish a {TCPClient#write}.
198
+ # The maximum time in seconds to write to a connection.
198
199
  #
199
- # @return [Numeric] maximum time in seconds to finish a {TCPClient#write} request
200
- # @return [nil] if the write time should not be checked (default)
200
+ # @return [Numeric] maximum time in seconds
201
+ # @return [nil] if the write time should not be monitored (default)
202
+ #
203
+ # @see TCPClient#write
201
204
  #
202
205
  attr_reader :write_timeout
203
206
 
@@ -206,7 +209,10 @@ class TCPClient
206
209
  end
207
210
 
208
211
  #
209
- # @return [Class] exception class raised if a {TCPClient#write} timed out
212
+ # The exception class which will be raised if {TCPClient#write} can not be
213
+ # finished in time.
214
+ #
215
+ # @return [Class<Exception>] exception class raised
210
216
  # @raise [NotAnExceptionError] if given argument is not an Exception class
211
217
  #
212
218
  attr_reader :write_timeout_error
@@ -217,48 +223,78 @@ class TCPClient
217
223
  end
218
224
 
219
225
  #
220
- # @attribute ssl?
221
- # @return [Boolean] wheter SSL is configured, see {#ssl_params}
226
+ # @attribute [w] timeout
227
+ # Shorthand to set maximum time in seconds for all timeout monitoring.
222
228
  #
223
- def ssl?
224
- @ssl_params ? true : false
229
+ # @return [Numeric] maximum time in seconds for any actwion
230
+ # @return [nil] if all timeout monitoring should be disabled (default)
231
+ #
232
+ # @see #connect_timeout
233
+ # @see #read_timeout
234
+ # @see #write_timeout
235
+ #
236
+ def timeout=(value)
237
+ @connect_timeout = @write_timeout = @read_timeout = seconds(value)
225
238
  end
226
239
 
227
240
  #
228
- # Configures the SSL parameters used to initialize a SSL context.
241
+ # @attribute [w] timeout_error
242
+ # Shorthand to set the exception class wich will by raised by any reached
243
+ # timeout.
229
244
  #
230
- # @return [Hash<Symbol, Object>] SSL parameters for the SSL context
231
- # @return [nil] if no SSL should be used (default)
245
+ # @return [Class<Exception>] exception class raised
232
246
  #
233
- attr_reader :ssl_params
247
+ # @raise [NotAnExceptionError] if given argument is not an Exception class
248
+ #
249
+ # @see #connect_timeout_error
250
+ # @see #read_timeout_error
251
+ # @see #write_timeout_error
252
+ #
253
+ def timeout_error=(value)
254
+ raise(NotAnExceptionError, value) unless exception_class?(value)
255
+ @connect_timeout_error =
256
+ @read_timeout_error = @write_timeout_error = value
257
+ end
234
258
 
235
- def ssl_params=(value)
236
- @ssl_params =
237
- if value.respond_to?(:to_hash)
238
- Hash[value.to_hash]
239
- elsif value.respond_to?(:to_h)
240
- Hash[value.to_h]
241
- else
242
- value ? {} : nil
243
- end
259
+ # @!endgroup
260
+
261
+ #
262
+ # Enables/disables if network exceptions should be raised as {NetworkError}.
263
+ #
264
+ # This allows to handle all network/socket related exceptions like
265
+ # `SocketError`, `OpenSSL::SSL::SSLError`, `IOError`, etc. in a uniform
266
+ # manner. If this option is set to true all these error cases are raised as
267
+ # {NetworkError} and can be easily captured.
268
+ #
269
+ # @return [Boolean] wheter all network exceptions should be raised as
270
+ # {NetworkError}, or not (default)
271
+ #
272
+ attr_reader :normalize_network_errors
273
+
274
+ def normalize_network_errors=(value)
275
+ @normalize_network_errors = value ? true : false
244
276
  end
245
- alias ssl= ssl_params=
246
277
 
247
278
  #
248
- # @return [Hash] configuration as a Hash
279
+ # Convert `self` to a Hash containing all attributes.
280
+ #
281
+ # @return [Hash<Symbol, Object>]
282
+ #
283
+ # @see #initialize
249
284
  #
250
285
  def to_h
251
286
  {
252
287
  buffered: @buffered,
253
288
  keep_alive: @keep_alive,
254
289
  reverse_lookup: @reverse_lookup,
290
+ ssl_params: @ssl_params,
255
291
  connect_timeout: @connect_timeout,
256
292
  connect_timeout_error: @connect_timeout_error,
257
293
  read_timeout: @read_timeout,
258
294
  read_timeout_error: @read_timeout_error,
259
295
  write_timeout: @write_timeout,
260
296
  write_timeout_error: @write_timeout_error,
261
- ssl_params: @ssl_params
297
+ normalize_network_errors: @normalize_network_errors
262
298
  }
263
299
  end
264
300
 
@@ -2,8 +2,6 @@
2
2
 
3
3
  class TCPClient
4
4
  class Deadline
5
- MONOTONIC = defined?(Process::CLOCK_MONOTONIC) ? true : false
6
-
7
5
  def initialize(timeout)
8
6
  timeout = timeout&.to_f
9
7
  @deadline = timeout&.positive? ? now + timeout : 0
@@ -19,7 +17,7 @@ class TCPClient
19
17
 
20
18
  private
21
19
 
22
- if MONOTONIC
20
+ if defined?(Process::CLOCK_MONOTONIC)
23
21
  def now
24
22
  Process.clock_gettime(Process::CLOCK_MONOTONIC)
25
23
  end
@@ -7,13 +7,17 @@ class TCPClient
7
7
 
8
8
  class << self
9
9
  #
10
- # @return [Configuration] used by default if no dedicated configuration was specified
10
+ # The default configuration.
11
+ # This is used by default if no dedicated configuration was specified to
12
+ # {.open} or {#connect}.
13
+ #
14
+ # @return [Configuration]
11
15
  #
12
16
  attr_reader :default_configuration
13
17
 
14
18
  #
15
- # Configure the default configuration which is used if no dedicated
16
- # configuration was specified.
19
+ # Configure the {.default_configuration} which is used if no dedicated
20
+ # configuration was specified to {.open} or {#connect}.
17
21
  #
18
22
  # @example
19
23
  # TCPClient.configure do |cfg|
@@ -33,11 +37,19 @@ class TCPClient
33
37
  end
34
38
 
35
39
  class Configuration
36
- #
37
- # @return [Configuration] used by default if no dedicated configuration was specified
38
- #
39
- def self.default
40
- TCPClient.default_configuration
40
+ class << self
41
+ #
42
+ # @!parse attr_reader :default
43
+ # @return [Configuration] used by default if no dedicated configuration
44
+ # was specified
45
+ #
46
+ # @see TCPClient.open
47
+ # @see TCPClient.with_deadline
48
+ # @see TCPClient#connect
49
+ #
50
+ def default
51
+ TCPClient.default_configuration
52
+ end
41
53
  end
42
54
  end
43
55
  end
@@ -2,7 +2,8 @@
2
2
 
3
3
  class TCPClient
4
4
  #
5
- # Raised when a SSL connection should be establshed but the OpenSSL gem is not available.
5
+ # Raised when a SSL connection should be establshed but the OpenSSL gem is
6
+ # not available.
6
7
  #
7
8
  class NoOpenSSLError < RuntimeError
8
9
  def initialize
@@ -11,7 +12,8 @@ class TCPClient
11
12
  end
12
13
 
13
14
  #
14
- # Raised when a method requires a callback block but no such block is specified.
15
+ # Raised when a method requires a callback block but no such block is
16
+ # specified.
15
17
  #
16
18
  class NoBlockGivenError < ArgumentError
17
19
  def initialize
@@ -20,9 +22,12 @@ class TCPClient
20
22
  end
21
23
 
22
24
  #
23
- # Raised when a an invalid timeout value was specified.
25
+ # Raised when an invalid timeout value was specified.
24
26
  #
25
27
  class InvalidDeadLineError < ArgumentError
28
+ #
29
+ # @param timeout [Object] the invalid value
30
+ #
26
31
  def initialize(timeout)
27
32
  super("invalid deadline - #{timeout}")
28
33
  end
@@ -32,6 +37,9 @@ class TCPClient
32
37
  # Raised by {Configuration} when an undefined attribute should be set.
33
38
  #
34
39
  class UnknownAttributeError < ArgumentError
40
+ #
41
+ # @param attribute [Object] the undefined atttribute
42
+ #
35
43
  def initialize(attribute)
36
44
  super("unknown attribute - #{attribute}")
37
45
  end
@@ -41,6 +49,9 @@ class TCPClient
41
49
  # Raised when a given timeout exception parameter is not an exception class.
42
50
  #
43
51
  class NotAnExceptionError < TypeError
52
+ #
53
+ # @param object [Object] the invalid object
54
+ #
44
55
  def initialize(object)
45
56
  super("exception class required - #{object.inspect}")
46
57
  end
@@ -49,15 +60,18 @@ class TCPClient
49
60
  #
50
61
  # Base exception class for all network related errors.
51
62
  #
52
- # Will be raised for any system level network error when {Configuration.normalize_network_errors} is configured.
63
+ # Will be raised for any system level network error when
64
+ # {Configuration.normalize_network_errors} is configured.
53
65
  #
54
- # You should catch this exception class when you like to handle any relevant {TCPClient} error.
66
+ # You should catch this exception class when you like to handle any relevant
67
+ # {TCPClient} error.
55
68
  #
56
69
  class NetworkError < StandardError
57
70
  end
58
71
 
59
72
  #
60
- # Raised when a {TCPClient} instance should read/write from/to the network but is not connected.
73
+ # Raised when a {TCPClient} instance should read/write from/to the network
74
+ # but is not connected.
61
75
  #
62
76
  class NotConnectedError < NetworkError
63
77
  def initialize
@@ -68,23 +82,26 @@ class TCPClient
68
82
  #
69
83
  # Base exception class for a detected timeout.
70
84
  #
71
- # You should catch this exception class when you like to handle any timeout error.
85
+ # You should catch this exception class when you like to handle any timeout
86
+ # error.
72
87
  #
73
88
  class TimeoutError < NetworkError
74
89
  #
75
90
  # Initializes the instance with an optional message.
76
91
  #
77
- # the message will be generated from {#action} when not specified.
92
+ # The message will be generated from {#action} when not specified.
93
+ #
78
94
  # @overload initialize
79
95
  # @overload initialize(message)
80
96
  #
81
- # @param message [String, #to_s] the error message
97
+ # @param message [#to_s] the error message
82
98
  #
83
99
  def initialize(message = nil)
84
100
  super(message || "unable to #{action} in time")
85
101
  end
86
102
 
87
103
  #
104
+ # @attribute [r] action
88
105
  # @return [Symbol] the action which timed out
89
106
  #
90
107
  def action
@@ -97,7 +114,8 @@ class TCPClient
97
114
  #
98
115
  class ConnectTimeoutError < TimeoutError
99
116
  #
100
- # @return [Symbol] the action which timed out: +:connect+
117
+ # @attribute [r] action
118
+ # @return [Symbol] the action which timed out: `:connect`
101
119
  #
102
120
  def action
103
121
  :connect
@@ -105,11 +123,12 @@ class TCPClient
105
123
  end
106
124
 
107
125
  #
108
- # Raised by default whenever a {TCPClient.read} timed out.
126
+ # Raised by default whenever a {TCPClient#read} timed out.
109
127
  #
110
128
  class ReadTimeoutError < TimeoutError
111
129
  #
112
- # @return [Symbol] the action which timed out: +:read+
130
+ # @attribute [r] action
131
+ # @return [Symbol] the action which timed out: :read`
113
132
  #
114
133
  def action
115
134
  :read
@@ -117,11 +136,12 @@ class TCPClient
117
136
  end
118
137
 
119
138
  #
120
- # Raised by default whenever a {TCPClient.write} timed out.
139
+ # Raised by default whenever a {TCPClient#write} timed out.
121
140
  #
122
141
  class WriteTimeoutError < TimeoutError
123
142
  #
124
- # @return [Symbol] the action which timed out: +:write+
143
+ # @attribute [r] action
144
+ # @return [Symbol] the action which timed out: `:write`
125
145
  #
126
146
  def action
127
147
  :write
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class TCPClient
4
- #
5
- # The current gem version.
6
- #
7
- VERSION = '0.9.0'
4
+ VERSION = '0.9.4'
8
5
  end
data/lib/tcp-client.rb CHANGED
@@ -15,7 +15,7 @@ require_relative 'tcp-client/version'
15
15
  # All connect/read/write actions can be monitored to ensure that all actions
16
16
  # terminate before given time limits - or raise an exception.
17
17
  #
18
- # @example - request to Google.com and limit all network interactions to 1.5 seconds
18
+ # @example request to Google.com and limit network interactions to 1.5 seconds
19
19
  # TCPClient.with_deadline(1.5, 'www.google.com:443') do |client|
20
20
  # client.write("GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n")
21
21
  # client.read(12)
@@ -26,7 +26,17 @@ require_relative 'tcp-client/version'
26
26
  class TCPClient
27
27
  #
28
28
  # Creates a new instance which is connected to the server on the given
29
- # address and uses the given or the {.default_configuration}.
29
+ # `address`.
30
+ #
31
+ # If no `configuration` is given, the {.default_configuration} will be used.
32
+ #
33
+ # @overload open(address, configuration = nil)
34
+ # @yieldparam client [TCPClient] the connected client
35
+ #
36
+ # @return [Object] the block result
37
+ #
38
+ # @overload open(address, configuration = nil)
39
+ # @return [TCPClient] the connected client
30
40
  #
31
41
  # If an optional block is given, then the block's result is returned and the
32
42
  # connection will be closed when the block execution ends.
@@ -36,13 +46,10 @@ class TCPClient
36
46
  # If no block is giiven the connected client instance is returned.
37
47
  # This can be used as a shorthand to create & connect a client.
38
48
  #
39
- # @param address [Address, String, Addrinfo, Integer] the address to connect to, see {Address#initialize} for valid formats
40
- # @param configuration [Configuration] the {Configuration} to be used for this instance
41
- #
42
- # @yieldparam client [TCPClient] the connected client
43
- # @yieldreturn [Object] any result
44
- #
45
- # @return [Object, TCPClient] the block result or the connected client
49
+ # @param address [Address, String, Addrinfo, Integer] the target address see
50
+ # {Address#initialize} for valid formats
51
+ # @param configuration [Configuration] the {Configuration} to be used for
52
+ # the new instance
46
53
  #
47
54
  # @see #connect
48
55
  #
@@ -55,24 +62,29 @@ class TCPClient
55
62
  end
56
63
 
57
64
  #
58
- # Yields a new instance which is connected to the server on the given
59
- # address and uses the given or the {.default_configuration}.
60
- # It ensures to close the connection when the block execution ends.
61
- # It also limits all {#read} and {#write} actions within the block to a given
62
- # time.
65
+ # Yields an instance which is connected to the server on the given
66
+ # `address`. It limits all {#read} and {#write} actions within the block to
67
+ # the given time.
68
+ #
69
+ # It ensures to close the connection when the block execution ends and returns
70
+ # the block`s result.
63
71
  #
64
72
  # This can be used to create an ad-hoc connection which is garanteed to be
65
- # closed and which read/write calls should not last longer than the timeout
66
- # limit.
73
+ # closed and which {#read}/{#write} call sequence should not last longer than
74
+ # the `timeout` seconds.
75
+ #
76
+ # If no `configuration` is given, the {.default_configuration} will be used.
67
77
  #
68
- # @param timeout [Numeric] maximum time in seconds for all {#read} and {#write} calls within the block
69
- # @param address [Address, String, Addrinfo, Integer] the address to connect to, see {Address#initialize} for valid formats
70
- # @param configuration [Configuration] the {Configuration} to be used for this instance
78
+ # @param timeout [Numeric] maximum time in seconds for all {#read} and
79
+ # {#write} calls within the block
80
+ # @param address [Address, String, Addrinfo, Integer] the target address see
81
+ # {Address#initialize} for valid formats
82
+ # @param configuration [Configuration] the {Configuration} to be used for
83
+ # the instance
71
84
  #
72
85
  # @yieldparam client [TCPClient] the connected client
73
- # @yieldreturn [Object] any result
74
86
  #
75
- # @return [Object] the block result
87
+ # @return [Object] the block's result
76
88
  #
77
89
  # @see #with_deadline
78
90
  #
@@ -89,89 +101,135 @@ class TCPClient
89
101
  end
90
102
 
91
103
  #
92
- # @return [Address] the address used for this client
104
+ # @return [Address] the address used by this client instance
93
105
  #
94
106
  attr_reader :address
95
107
 
96
108
  #
97
- # @return [Configuration] the configuration used by this client.
109
+ # @return [Configuration] the configuration used by this client instance
98
110
  #
99
111
  attr_reader :configuration
100
112
 
101
113
  #
102
- # @attribute [r] closed?
103
- # @return [Boolean] true when the connection is closed, false when connected
114
+ # @!parse attr_reader :closed?
115
+ # @return [Boolean] wheter the connection is closed
104
116
  #
105
117
  def closed?
106
118
  @socket.nil? || @socket.closed?
107
119
  end
108
120
 
109
121
  #
110
- # @return [String] the currently used address as text.
122
+ # Close the current connection if connected.
111
123
  #
112
- # @see Address#to_s
124
+ # @return [self]
113
125
  #
114
- def to_s
115
- @address&.to_s || ''
126
+ def close
127
+ @socket&.close
128
+ self
129
+ rescue *NETWORK_ERRORS
130
+ self
131
+ ensure
132
+ @socket = @deadline = nil
116
133
  end
117
134
 
118
135
  #
119
- # Establishes a new connection to a given address.
136
+ # Establishes a new connection to a given `address`.
120
137
  #
121
- # It accepts a connection-specific configuration or uses the global {.default_configuration}. The {#configuration} used by this instance will
122
- # be a copy of the configuration used for this method call. This allows to
123
- # configure the behavior per connection.
138
+ # It accepts a connection-specific `configuration` or uses the
139
+ # {.default_configuration}.
124
140
  #
125
- # @param address [Address, String, Addrinfo, Integer] the address to connect to, see {Address#initialize} for valid formats
126
- # @param configuration [Configuration] the {Configuration} to be used for this instance
127
- # @param timeout [Numeric] maximum time in seconds to read; used to override the configuration's +connect_timeout+.
128
- # @param exception [Class] exception class to be used when the read timeout reached; used to override the configuration's +connect_timeout_error+.
141
+ # The optional `timeout` and `exception` parameters allow to override the
142
+ # `connect_timeout` and `connect_timeout_error` values.
143
+ #
144
+ # @param address [Address, String, Addrinfo, Integer] the target address see
145
+ # {Address#initialize} for valid formats
146
+ # @param configuration [Configuration] the {Configuration} to be used for
147
+ # this instance
148
+ # @param timeout [Numeric] maximum time in seconds to connect
149
+ # @param exception [Class<Exception>] exception class to be used when the
150
+ # connect timeout reached
129
151
  #
130
152
  # @return [self]
131
153
  #
132
154
  # @raise {NoOpenSSLError} if SSL should be used but OpenSSL is not avail
133
155
  #
156
+ # @see NetworkError
157
+ #
134
158
  def connect(address, configuration = nil, timeout: nil, exception: nil)
135
159
  close if @socket
136
- raise(NoOpenSSLError) if configuration.ssl? && !defined?(SSLSocket)
137
160
  @address = Address.new(address)
138
161
  @configuration = (configuration || Configuration.default).dup
162
+ raise(NoOpenSSLError) if @configuration.ssl? && !defined?(SSLSocket)
139
163
  @socket = create_socket(timeout, exception)
140
164
  self
141
165
  end
142
166
 
143
167
  #
144
- # Close the current connection.
168
+ # Flushes all internal buffers (write all through).
145
169
  #
146
170
  # @return [self]
147
171
  #
148
- def close
149
- @socket&.close
150
- self
151
- rescue *NETWORK_ERRORS
172
+ def flush
173
+ stem_errors { @socket&.flush }
152
174
  self
153
- ensure
154
- @socket = @deadline = nil
155
175
  end
156
176
 
157
177
  #
158
- # Executes a block with a given overall timeout.
178
+ # Read the given `nbytes` or the next available buffer from server.
179
+ #
180
+ # The optional `timeout` and `exception` parameters allow to override the
181
+ # `read_timeout` and `read_timeout_error` values of the used {#configuration}.
182
+ #
183
+ # @param nbytes [Integer] the number of bytes to read
184
+ # @param timeout [Numeric] maximum time in seconds to read
185
+ # @param exception [Class<Exception>] exception class to be used when the
186
+ # read timeout reached
187
+ #
188
+ # @return [String] the read buffer
189
+ #
190
+ # @raise [NotConnectedError] if {#connect} was not called before
191
+ #
192
+ # @see NetworkError
193
+ #
194
+ def read(nbytes = nil, timeout: nil, exception: nil)
195
+ raise(NotConnectedError) if closed?
196
+ deadline = create_deadline(timeout, configuration.read_timeout)
197
+ return stem_errors { @socket.read(nbytes) } unless deadline.valid?
198
+ exception ||= configuration.read_timeout_error
199
+ stem_errors(exception) do
200
+ @socket.read_with_deadline(nbytes, deadline, exception)
201
+ end
202
+ end
203
+
204
+ #
205
+ # @return [String] the currently used address as text.
159
206
  #
160
- # When you like to ensure that a complete read/write communication sequence
161
- # with the server is finished before a given amount of time you can use this
162
- # method to define such a deadline.
207
+ # @see Address#to_s
163
208
  #
164
- # @example - ensure to send a welcome message and receive a 64 byte answer from server
209
+ def to_s
210
+ @address&.to_s || ''
211
+ end
212
+
213
+ #
214
+ # Executes a block with a given overall time limit.
215
+ #
216
+ # When you like to ensure that a complete {#read}/{#write} communication
217
+ # sequence with the server is finished before a given amount of time you use
218
+ # this method.
219
+ #
220
+ # @example ensure to send SMTP welcome message and receive a 4 byte answer
165
221
  # answer = client.with_deadline(2.5) do
166
- # client.write('Helo')
167
- # client.read(64)
222
+ # client.write('HELO')
223
+ # client.read(4)
168
224
  # end
225
+ # # answer is EHLO when server speaks fluent SMPT
169
226
  #
170
- # @param timeout [Numeric] maximum time in seconds for all {#read} and {#write} calls within the block
227
+ # @param timeout [Numeric] maximum time in seconds for all {#read} and
228
+ # {#write} calls within the block
171
229
  #
172
230
  # @yieldparam client [TCPClient] self
173
231
  #
174
- # @return [Object] result of the given block
232
+ # @return [Object] the block`s result
175
233
  #
176
234
  # @raise [NoBlockGivenError] if the block is missing
177
235
  #
@@ -186,32 +244,16 @@ class TCPClient
186
244
  end
187
245
 
188
246
  #
189
- # Read the given nbytes or the next available buffer from server.
190
- #
191
- # @param nbytes [Integer] the number of bytes to read
192
- # @param timeout [Numeric] maximum time in seconds to read; used to override the configuration's +read_timeout+.
193
- # @param exception [Class] exception class to be used when the read timeout reached; used to override the configuration's +read_timeout_error+.
194
- #
195
- # @return [String] buffer read
196
- #
197
- # @raise [NotConnectedError] if {#connect} was not called before
247
+ # Writes the given `messages` to the server.
198
248
  #
199
- def read(nbytes = nil, timeout: nil, exception: nil)
200
- raise(NotConnectedError) if closed?
201
- deadline = create_deadline(timeout, configuration.read_timeout)
202
- return stem_errors { @socket.read(nbytes) } unless deadline.valid?
203
- exception ||= configuration.read_timeout_error
204
- stem_errors(exception) do
205
- @socket.read_with_deadline(nbytes, deadline, exception)
206
- end
207
- end
208
-
249
+ # The optional `timeout` and `exception` parameters allow to override the
250
+ # `write_timeout` and `write_timeout_error` values of the used
251
+ # {#configuration}.
209
252
  #
210
- # Write the given messages to the server.
211
- #
212
- # @param messages [Array<String>] messages to write
213
- # @param timeout [Numeric] maximum time in seconds to read; used to override the configuration's +write_timeout+.
214
- # @param exception [Class] exception class to be used when the read timeout reached; used to override the configuration's +write_timeout_error+.
253
+ # @param messages [Array<String>] one or more messages to write
254
+ # @param timeout [Numeric] maximum time in seconds to write
255
+ # @param exception [Class<Exception>] exception class to be used when the
256
+ # write timeout reached
215
257
  #
216
258
  # @return [Integer] bytes written
217
259
  #
@@ -229,16 +271,6 @@ class TCPClient
229
271
  end
230
272
  end
231
273
 
232
- #
233
- # Flush all internal buffers (write all through).
234
- #
235
- # @return [self]
236
- #
237
- def flush
238
- stem_errors { @socket&.flush }
239
- self
240
- end
241
-
242
274
  private
243
275
 
244
276
  def create_deadline(timeout, default)
@@ -277,4 +309,5 @@ class TCPClient
277
309
  ].tap do |errors|
278
310
  errors << ::OpenSSL::SSL::SSLError if defined?(::OpenSSL::SSL::SSLError)
279
311
  end.freeze
312
+ private_constant(:NETWORK_ERRORS)
280
313
  end
data/rakefile.rb CHANGED
@@ -6,8 +6,7 @@ require 'rspec/core/rake_task'
6
6
  require 'yard'
7
7
 
8
8
  $stdout.sync = $stderr.sync = true
9
-
10
- CLOBBER << 'prj' << 'doc'
9
+ CLOBBER << 'prj' << 'doc' << '.yardoc'
11
10
  task(:default) { exec('rake --tasks') }
12
11
  RSpec::Core::RakeTask.new { |task| task.ruby_opts = %w[-w] }
13
12
  YARD::Rake::YardocTask.new { |task| task.stats_options = %w[--list-undoc] }
@@ -9,8 +9,8 @@ RSpec.describe TCPClient::Address do
9
9
 
10
10
  it 'points to the given port on localhost' do
11
11
  expect(address.hostname).to eq 'localhost'
12
+ expect(address.port).to be 42
12
13
  expect(address.to_s).to eq 'localhost:42'
13
- expect(address.addrinfo.ip_port).to be 42
14
14
  end
15
15
 
16
16
  it 'uses IPv6' do
@@ -29,8 +29,9 @@ RSpec.describe TCPClient::Address do
29
29
  end
30
30
 
31
31
  it 'points to the given host and port' do
32
- expect(address.hostname).to eq addrinfo.getnameinfo[0]
33
- expect(address.addrinfo.ip_port).to be 42
32
+ expect(address.hostname).to eq 'localhost'
33
+ expect(address.port).to be 42
34
+ expect(address.to_s).to eq 'localhost:42'
34
35
  end
35
36
 
36
37
  it 'uses IPv6' do
@@ -46,30 +47,21 @@ RSpec.describe TCPClient::Address do
46
47
 
47
48
  it 'points to the given host and port' do
48
49
  expect(address.hostname).to eq 'localhost'
50
+ expect(address.port).to be 42
49
51
  expect(address.to_s).to eq 'localhost:42'
50
- expect(address.addrinfo.ip_port).to be 42
51
- end
52
-
53
- it 'uses IPv6' do
54
52
  expect(address.addrinfo.ip?).to be true
55
- expect(address.addrinfo.ipv6?).to be true
56
- expect(address.addrinfo.ipv4?).to be false
57
53
  end
54
+
58
55
  end
59
56
 
60
57
  context 'when only a port is provided' do
61
- subject(:address) { TCPClient::Address.new(':21') }
58
+ subject(:address) { TCPClient::Address.new(':42') }
62
59
 
63
60
  it 'points to the given port on localhost' do
64
- expect(address.hostname).to eq ''
65
- expect(address.to_s).to eq ':21'
66
- expect(address.addrinfo.ip_port).to be 21
67
- end
68
-
69
- it 'uses IPv4' do
61
+ expect(address.hostname).to eq 'localhost'
62
+ expect(address.port).to be 42
63
+ expect(address.to_s).to eq 'localhost:42'
70
64
  expect(address.addrinfo.ip?).to be true
71
- expect(address.addrinfo.ipv6?).to be false
72
- expect(address.addrinfo.ipv4?).to be true
73
65
  end
74
66
  end
75
67
 
@@ -78,14 +70,9 @@ RSpec.describe TCPClient::Address do
78
70
 
79
71
  it 'points to the given port on localhost' do
80
72
  expect(address.hostname).to eq '::1'
73
+ expect(address.port).to be 42
81
74
  expect(address.to_s).to eq '[::1]:42'
82
- expect(address.addrinfo.ip_port).to be 42
83
- end
84
-
85
- it 'uses IPv6' do
86
75
  expect(address.addrinfo.ip?).to be true
87
- expect(address.addrinfo.ipv6?).to be true
88
- expect(address.addrinfo.ipv4?).to be false
89
76
  end
90
77
  end
91
78
  end
@@ -108,13 +95,13 @@ RSpec.describe TCPClient::Address do
108
95
  expect(address_a).to eq address_b
109
96
  end
110
97
 
111
- context 'using the == opperator' do
98
+ context 'using the == operator' do
112
99
  it 'compares to equal' do
113
100
  expect(address_a == address_b).to be true
114
101
  end
115
102
  end
116
103
 
117
- context 'using the === opperator' do
104
+ context 'using the === operator' do
118
105
  it 'compares to equal' do
119
106
  expect(address_a === address_b).to be true
120
107
  end
@@ -129,13 +116,13 @@ RSpec.describe TCPClient::Address do
129
116
  expect(address_a).not_to eq address_b
130
117
  end
131
118
 
132
- context 'using the == opperator' do
119
+ context 'using the == operator' do
133
120
  it 'compares not to equal' do
134
121
  expect(address_a == address_b).to be false
135
122
  end
136
123
  end
137
124
 
138
- context 'using the === opperator' do
125
+ context 'using the === operator' do
139
126
  it 'compares not to equal' do
140
127
  expect(address_a === address_b).to be false
141
128
  end
@@ -82,7 +82,7 @@ RSpec.describe TCPClient::Configuration do
82
82
  expect(configuration.keep_alive).to be false
83
83
  end
84
84
 
85
- it 'allows to configure reverse address lokup' do
85
+ it 'allows to configure reverse address lookup' do
86
86
  expect(configuration.reverse_lookup).to be false
87
87
  end
88
88
 
@@ -148,7 +148,7 @@ RSpec.describe TCPClient::Configuration do
148
148
  end
149
149
  end
150
150
 
151
- context 'with invalid attribte' do
151
+ context 'with invalid attribute' do
152
152
  it 'raises an error' do
153
153
  expect { TCPClient::Configuration.new(invalid: :value) }.to raise_error(
154
154
  TCPClient::UnknownAttributeError
@@ -182,6 +182,7 @@ RSpec.describe TCPClient::Configuration do
182
182
  read_timeout_error: TCPClient::ReadTimeoutError,
183
183
  write_timeout: 3,
184
184
  write_timeout_error: TCPClient::WriteTimeoutError,
185
+ normalize_network_errors: false,
185
186
  ssl_params: {
186
187
  min_version: :TLS1_2,
187
188
  max_version: :TLS1_3
@@ -232,13 +233,13 @@ RSpec.describe TCPClient::Configuration do
232
233
  expect(config_a).to eq config_b
233
234
  end
234
235
 
235
- context 'using the == opperator' do
236
+ context 'using the == operator' do
236
237
  it 'compares to equal' do
237
238
  expect(config_a == config_b).to be true
238
239
  end
239
240
  end
240
241
 
241
- context 'using the === opperator' do
242
+ context 'using the === operator' do
242
243
  it 'compares to equal' do
243
244
  expect(config_a === config_b).to be true
244
245
  end
@@ -253,13 +254,13 @@ RSpec.describe TCPClient::Configuration do
253
254
  expect(config_a).not_to eq config_b
254
255
  end
255
256
 
256
- context 'using the == opperator' do
257
+ context 'using the == operator' do
257
258
  it 'compares not to equal' do
258
259
  expect(config_a == config_b).to be false
259
260
  end
260
261
  end
261
262
 
262
- context 'using the === opperator' do
263
+ context 'using the === operator' do
263
264
  it 'compares not to equal' do
264
265
  expect(config_a === config_b).to be false
265
266
  end
data/tcp-client.gemspec CHANGED
@@ -5,12 +5,11 @@ require_relative './lib/tcp-client/version'
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = 'tcp-client'
7
7
  spec.version = TCPClient::VERSION
8
- spec.author = 'Mike Blumtritt'
9
-
10
8
  spec.required_ruby_version = '>= 2.7.0'
11
9
 
10
+ spec.author = 'Mike Blumtritt'
12
11
  spec.summary = 'A TCP client implementation with working timeout support.'
13
- spec.description = <<~DESCRIPTION
12
+ spec.description = <<~description
14
13
  This Gem implements a TCP client with (optional) SSL support.
15
14
  It is an easy to use, versatile configurable client that can correctly
16
15
  handle time limits.
@@ -18,13 +17,15 @@ Gem::Specification.new do |spec|
18
17
  predefined/configurable time limits for each method
19
18
  (`connect`, `read`, `write`). Deadlines for a sequence of read/write
20
19
  actions can also be monitored.
21
- DESCRIPTION
20
+ description
21
+
22
22
  spec.homepage = 'https://github.com/mblumtritt/tcp-client'
23
23
  spec.license = 'BSD-3-Clause'
24
-
25
- spec.metadata['source_code_uri'] = 'https://github.com/mblumtritt/tcp-client'
26
- spec.metadata['bug_tracker_uri'] =
27
- 'https://github.com/mblumtritt/tcp-client/issues'
24
+ spec.metadata.merge!(
25
+ 'source_code_uri' => 'https://github.com/mblumtritt/tcp-client',
26
+ 'bug_tracker_uri' => 'https://github.com/mblumtritt/tcp-client/issues',
27
+ 'documentation_uri' => 'https://rubydoc.info/github/mblumtritt/tcp-client'
28
+ )
28
29
 
29
30
  spec.add_development_dependency 'bundler'
30
31
  spec.add_development_dependency 'rake'
@@ -34,6 +35,5 @@ Gem::Specification.new do |spec|
34
35
  all_files = Dir.chdir(__dir__) { `git ls-files -z`.split(0.chr) }
35
36
  spec.test_files = all_files.grep(%r{^spec/})
36
37
  spec.files = all_files - spec.test_files
37
-
38
38
  spec.extra_rdoc_files = %w[README.md LICENSE]
39
39
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tcp-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Blumtritt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-01 00:00:00.000000000 Z
11
+ date: 2021-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -82,6 +82,7 @@ extra_rdoc_files:
82
82
  - LICENSE
83
83
  files:
84
84
  - ".gitignore"
85
+ - ".yardopts"
85
86
  - LICENSE
86
87
  - README.md
87
88
  - gems.rb
@@ -112,6 +113,7 @@ licenses:
112
113
  metadata:
113
114
  source_code_uri: https://github.com/mblumtritt/tcp-client
114
115
  bug_tracker_uri: https://github.com/mblumtritt/tcp-client/issues
116
+ documentation_uri: https://rubydoc.info/github/mblumtritt/tcp-client
115
117
  post_install_message:
116
118
  rdoc_options: []
117
119
  require_paths:
@@ -127,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
129
  - !ruby/object:Gem::Version
128
130
  version: '0'
129
131
  requirements: []
130
- rubygems_version: 3.2.28
132
+ rubygems_version: 3.2.32
131
133
  signing_key:
132
134
  specification_version: 4
133
135
  summary: A TCP client implementation with working timeout support.