tcp-client 0.9.0 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
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.