tcp-client 0.10.1 → 0.11.2

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: 02440fe17a1480ba18bec8b6918cea6420a065d997c423a6602e165e0f316564
4
- data.tar.gz: 73e315f2c80a2f0f1cf0cb57b24f2f2cd45e10caffebd83dd47510ea85de1f25
3
+ metadata.gz: 4665e444c265a00de59f416c23db910d3ed7a96fc62ba6bf966c4e14b6564a9e
4
+ data.tar.gz: 04c8e56bd884b61d5f5219233aa6bdfd7d2ce89c0f5892deebe27029e436ec4b
5
5
  SHA512:
6
- metadata.gz: bb22bb974aacd8cfc9d4a1ebcc66393172ec949db8038ecbc37c1a4187bb8a1d703206625f25fb7dba5e336217d2de31475220aa4147bc20df26a5deff7bd7b7
7
- data.tar.gz: 0fd048dda8d10ba76659276cd7f5c09e1fba73560d482a5cbbb35ba6db034192137552531dcd294d45a50a10a211839b318015d0546ded7df28c8f55246fe7fd
6
+ metadata.gz: a40b4af0dbe5c65c3a52b0250206ab31442c7efd34df1916293a60299ef87f73d0bb0e3cc0ab4bd5ad4d5a401035fb7f9939f60fc0ef1873a945663387253221
7
+ data.tar.gz: e4333df6c2ca755f8054bd6bee511835ae20965b1784c613f21545e4fc999f8e8b52da8d5c389528a473b779e1a9b5c87348474599daf47356e7081820da535d
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # TCPClient
2
2
 
3
- A TCP client implementation with working timeout support.
3
+ Use your TCP connections with working timeout.
4
4
 
5
5
  - Gem: [rubygems.org](https://rubygems.org/gems/tcp-client)
6
6
  - Source: [github.com](https://github.com/mblumtritt/tcp-client)
@@ -8,7 +8,8 @@ A TCP client implementation with working timeout support.
8
8
 
9
9
  ## Description
10
10
 
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.
11
+ This gem implements a customizable TCP client class that gives you control over time limits. You can set time limits for individual read or write calls or set a deadline for entire call sequences.
12
+ It has a very small footprint, no dependencies and is easily useable.
12
13
 
13
14
  ## Sample
14
15
 
@@ -37,7 +38,7 @@ response =
37
38
  puts(response)
38
39
  ```
39
40
 
40
- For more samples see [the samples dir](https://github.com/mblumtritt/tcp-client/tree/main/sample)
41
+ For more samples see [the examples dir](https://github.com/mblumtritt/tcp-client/tree/main/examples)
41
42
 
42
43
  ## Installation
43
44
 
@@ -61,7 +62,7 @@ To install the gem globally use:
61
62
  gem install tcp-client
62
63
  ```
63
64
 
64
- After that you need only a single line of code in your project to have all tools on board:
65
+ After that you need only a single line of code in your project to have it on board:
65
66
 
66
67
  ```ruby
67
68
  require 'tcp-client'
@@ -30,40 +30,25 @@ class TCPClient
30
30
  #
31
31
  # @return [Configuration] the initialized configuration
32
32
  #
33
- def self.create(options = {})
33
+ def self.create(options = nil)
34
34
  configuration = new(options)
35
35
  yield(configuration) if block_given?
36
36
  configuration
37
37
  end
38
38
 
39
39
  #
40
- # Initializes the instance with given options.
40
+ # Initializes and optionally configures the instance with given options.
41
41
  #
42
- # @param options [{Symbol => Object}]
43
- # @option options [Boolean] :buffered, see {#buffered}
44
- # @option options [Boolean] :keep_alive, see {#keep_alive}
45
- # @option options [Boolean] :reverse_lookup, see {#reverse_lookup}
46
- # @option options [{Symbol => Object}] :ssl_params, see {#ssl_params}
47
- # @option options [Numeric] :connect_timeout, see {#connect_timeout}
48
- # @option options [Class<Exception>] :connect_timeout_error, see
49
- # {#connect_timeout_error}
50
- # @option options [Numeric] :read_timeout, see {#read_timeout}
51
- # @option options [Class<Exception>] :read_timeout_error, see
52
- # {#read_timeout_error}
53
- # @option options [Numeric] :write_timeout, see {#write_timeout}
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}
42
+ # @see #configure
58
43
  #
59
- def initialize(options = {})
44
+ def initialize(options = nil)
60
45
  @buffered = @keep_alive = @reverse_lookup = true
61
46
  self.timeout = @ssl_params = nil
62
47
  @connect_timeout_error = ConnectTimeoutError
63
48
  @read_timeout_error = ReadTimeoutError
64
49
  @write_timeout_error = WriteTimeoutError
65
50
  @normalize_network_errors = false
66
- options.each_pair { |attribute, value| set(attribute, value) }
51
+ configure(options) if options
67
52
  end
68
53
 
69
54
  # @!group Instance Attributes Socket Level
@@ -257,6 +242,8 @@ class TCPClient
257
242
 
258
243
  # @!endgroup
259
244
 
245
+ # @!group Other Instance Attributes
246
+
260
247
  #
261
248
  # Enables/disables if network exceptions should be raised as {NetworkError}.
262
249
  #
@@ -274,10 +261,12 @@ class TCPClient
274
261
  @normalize_network_errors = value ? true : false
275
262
  end
276
263
 
264
+ # @!endgroup
265
+
277
266
  #
278
267
  # @return [{Symbol => Object}] Hash containing all attributes
279
268
  #
280
- # @see #initialize
269
+ # @see #configure
281
270
  #
282
271
  def to_h
283
272
  {
@@ -295,6 +284,33 @@ class TCPClient
295
284
  }
296
285
  end
297
286
 
287
+ #
288
+ # Configures the instance with given options Hash.
289
+ #
290
+ # @param options [{Symbol => Object}]
291
+ # @option options [Boolean] :buffered, see {#buffered}
292
+ # @option options [Boolean] :keep_alive, see {#keep_alive}
293
+ # @option options [Boolean] :reverse_lookup, see {#reverse_lookup}
294
+ # @option options [{Symbol => Object}] :ssl_params, see {#ssl_params}
295
+ # @option options [Numeric] :connect_timeout, see {#connect_timeout}
296
+ # @option options [Class<Exception>] :connect_timeout_error, see
297
+ # {#connect_timeout_error}
298
+ # @option options [Numeric] :read_timeout, see {#read_timeout}
299
+ # @option options [Class<Exception>] :read_timeout_error, see
300
+ # {#read_timeout_error}
301
+ # @option options [Numeric] :write_timeout, see {#write_timeout}
302
+ # @option options [Class<Exception>] :write_timeout_error, see
303
+ # {#write_timeout_error}
304
+ # @option options [Boolean] :normalize_network_errors, see
305
+ # {#normalize_network_errors}
306
+ #
307
+ # @return [Configuration] self
308
+ #
309
+ def configure(options)
310
+ options.each_pair { |attribute, value| set(attribute, value) }
311
+ self
312
+ end
313
+
298
314
  # @!visibility private
299
315
  def freeze
300
316
  @ssl_params.freeze
@@ -25,13 +25,13 @@ class TCPClient
25
25
  # cfg.ssl_params = { min_version: :TLS1_2, max_version: :TLS1_3 }
26
26
  # end
27
27
  #
28
- # @param options [Hash] see {Configuration#initialize} for details
28
+ # @param options [Hash] see {Configuration#configure} for details
29
29
  #
30
30
  # @yieldparam cfg {Configuration} the new configuration
31
31
  #
32
32
  # @return [Configuration] the new default configuration
33
33
  #
34
- def configure(options = {}, &block)
34
+ def configure(options = nil, &block)
35
35
  @default_configuration = Configuration.create(options, &block)
36
36
  end
37
37
  end
@@ -4,40 +4,35 @@ class TCPClient
4
4
  module IOWithDeadlineMixin
5
5
  def self.included(mod)
6
6
  methods = mod.instance_methods
7
- if methods.index(:wait_writable) && methods.index(:wait_readable)
8
- mod.include(ViaWaitMethod)
9
- elsif methods.index(:to_io)
10
- mod.include(ViaIOWaitMethod)
11
- else
12
- mod.include(ViaSelect)
13
- end
7
+ return if methods.index(:wait_writable) && methods.index(:wait_readable)
8
+ mod.include(methods.index(:to_io) ? WaitWithIO : WaitWithSelect)
14
9
  end
15
10
 
16
11
  def read_with_deadline(nbytes, deadline, exception)
17
12
  raise(exception) unless deadline.remaining_time
18
13
  return fetch_avail(deadline, exception) if nbytes.nil?
19
14
  return ''.b if nbytes.zero?
20
- @buf ||= ''.b
21
- while @buf.bytesize < nbytes
22
- read = fetch_next(deadline, exception) and next @buf << read
15
+ @read_buffer ||= ''.b
16
+ while @read_buffer.bytesize < nbytes
17
+ read = fetch_next(deadline, exception) and next @read_buffer << read
23
18
  close
24
19
  break
25
20
  end
26
- fetch_buffer_slice(nbytes)
21
+ fetch_slice(nbytes)
27
22
  end
28
23
 
29
- def readto_with_deadline(sep, deadline, exception)
24
+ def read_to_with_deadline(sep, deadline, exception)
30
25
  raise(exception) unless deadline.remaining_time
31
- @buf ||= ''.b
32
- while (index = @buf.index(sep)).nil?
33
- read = fetch_next(deadline, exception) and next @buf << read
26
+ @read_buffer ||= ''.b
27
+ while @read_buffer.index(sep).nil?
28
+ read = fetch_next(deadline, exception) and next @read_buffer << read
34
29
  close
35
30
  break
36
31
  end
37
- index = @buf.index(sep)
38
- return fetch_buffer_slice(index + sep.bytesize) if index
39
- result = @buf
40
- @buf = nil
32
+ index = @read_buffer.index(sep)
33
+ return fetch_slice(index + sep.bytesize) if index
34
+ result = @read_buffer
35
+ @read_buffer = nil
41
36
  result
42
37
  end
43
38
 
@@ -58,20 +53,18 @@ class TCPClient
58
53
  private
59
54
 
60
55
  def fetch_avail(deadline, exception)
61
- if @buf.nil?
62
- result = fetch_next(deadline, exception) and return result
56
+ if (result = @read_buffer || fetch_next(deadline, exception)).nil?
63
57
  close
64
58
  return ''.b
65
59
  end
66
- result = @buf
67
- @buf = nil
60
+ @read_buffer = nil
68
61
  result
69
62
  end
70
63
 
71
- def fetch_buffer_slice(size)
72
- result = @buf.byteslice(0, size)
73
- rest = @buf.bytesize - result.bytesize
74
- @buf = rest.zero? ? nil : @buf.byteslice(size, rest)
64
+ def fetch_slice(size)
65
+ result = @read_buffer.byteslice(0, size)
66
+ rest = @read_buffer.bytesize - result.bytesize
67
+ @read_buffer = rest.zero? ? nil : @read_buffer.byteslice(size, rest)
75
68
  result
76
69
  end
77
70
 
@@ -81,68 +74,44 @@ class TCPClient
81
74
  end
82
75
  end
83
76
 
84
- module ViaWaitMethod
85
- private def with_deadline(deadline, exception)
86
- loop do
87
- case ret = yield
88
- when :wait_writable
89
- remaining_time = deadline.remaining_time or raise(exception)
90
- raise(exception) if wait_writable(remaining_time).nil?
91
- when :wait_readable
92
- remaining_time = deadline.remaining_time or raise(exception)
93
- raise(exception) if wait_readable(remaining_time).nil?
94
- else
95
- return ret
96
- end
77
+ def with_deadline(deadline, exception)
78
+ loop do
79
+ case ret = yield
80
+ when :wait_writable
81
+ remaining_time = deadline.remaining_time or raise(exception)
82
+ raise(exception) if wait_writable(remaining_time).nil?
83
+ when :wait_readable
84
+ remaining_time = deadline.remaining_time or raise(exception)
85
+ raise(exception) if wait_readable(remaining_time).nil?
86
+ else
87
+ return ret
97
88
  end
98
- rescue Errno::ETIMEDOUT
99
- raise(exception)
100
89
  end
90
+ rescue Errno::ETIMEDOUT
91
+ raise(exception)
101
92
  end
102
93
 
103
- module ViaIOWaitMethod
104
- private def with_deadline(deadline, exception)
105
- loop do
106
- case ret = yield
107
- when :wait_writable
108
- remaining_time = deadline.remaining_time or raise(exception)
109
- raise(exception) if to_io.wait_writable(remaining_time).nil?
110
- when :wait_readable
111
- remaining_time = deadline.remaining_time or raise(exception)
112
- raise(exception) if to_io.wait_readable(remaining_time).nil?
113
- else
114
- return ret
115
- end
116
- end
117
- rescue Errno::ETIMEDOUT
118
- raise(exception)
94
+ module WaitWithIO
95
+ def wait_writable(remaining_time)
96
+ to_io.wait_writable(remaining_time)
97
+ end
98
+
99
+ def wait_readable(remaining_time)
100
+ to_io.wait_readable(remaining_time)
119
101
  end
120
102
  end
121
103
 
122
- module ViaSelect
123
- private def with_deadline(deadline, exception)
124
- loop do
125
- case ret = yield
126
- when :wait_writable
127
- remaining_time = deadline.remaining_time or raise(exception)
128
- if ::IO.select(nil, [self], nil, remaining_time).nil?
129
- raise(exception)
130
- end
131
- when :wait_readable
132
- remaining_time = deadline.remaining_time or raise(exception)
133
- if ::IO.select([self], nil, nil, remaining_time).nil?
134
- raise(exception)
135
- end
136
- else
137
- return ret
138
- end
139
- end
140
- rescue Errno::ETIMEDOUT
141
- raise(exception)
104
+ module WaitWithSelect
105
+ def wait_writable(remaining_time)
106
+ ::IO.select(nil, [self], nil, remaining_time)
107
+ end
108
+
109
+ def wait_readable(remaining_time)
110
+ ::IO.select([self], nil, nil, remaining_time)
142
111
  end
143
112
  end
144
113
 
145
- private_constant(:ViaWaitMethod, :ViaIOWaitMethod, :ViaSelect)
114
+ private_constant(:WaitWithIO, :WaitWithSelect)
146
115
  end
147
116
 
148
117
  private_constant(:IOWithDeadlineMixin)
@@ -2,5 +2,5 @@
2
2
 
3
3
  class TCPClient
4
4
  # The current version number.
5
- VERSION = '0.10.1'
5
+ VERSION = '0.11.2'
6
6
  end
data/lib/tcp-client.rb CHANGED
@@ -231,7 +231,7 @@ class TCPClient
231
231
  exception ||= configuration.read_timeout_error
232
232
  line =
233
233
  stem_errors(exception) do
234
- @socket.readto_with_deadline(separator, deadline, exception)
234
+ @socket.read_to_with_deadline(separator, deadline, exception)
235
235
  end
236
236
  chomp ? line.chomp : line
237
237
  end
@@ -344,7 +344,8 @@ class TCPClient
344
344
  IOError,
345
345
  SocketError
346
346
  ].tap do |errors|
347
- errors << ::OpenSSL::SSL::SSLError if defined?(::OpenSSL::SSL::SSLError)
348
- end.freeze
347
+ errors << ::OpenSSL::SSL::SSLError if defined?(::OpenSSL::SSL::SSLError)
348
+ end
349
+ .freeze
349
350
  private_constant(:NETWORK_ERRORS)
350
351
  end
metadata CHANGED
@@ -1,79 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tcp-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
4
+ version: 0.11.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Blumtritt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-12 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: rspec
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: yard
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
11
+ date: 2022-07-30 00:00:00.000000000 Z
12
+ dependencies: []
69
13
  description: |
70
- This Gem implements a TCP client with (optional) SSL support.
71
- It is an easy to use, versatile configurable client that can correctly
72
- handle time limits.
73
- Unlike other implementations, this client respects
74
- predefined/configurable time limits for each method
75
- (`connect`, `read`, `write`). Deadlines for a sequence of read/write
76
- actions can also be monitored.
14
+ This gem implements a customizable TCP client class that gives you control
15
+ over time limits. You can set time limits for individual read or write calls
16
+ or set a deadline for entire call sequences.
17
+ It has a very small footprint, no dependencies and is easily useable.
77
18
  email:
78
19
  executables: []
79
20
  extensions: []
@@ -81,11 +22,9 @@ extra_rdoc_files:
81
22
  - README.md
82
23
  - LICENSE
83
24
  files:
84
- - ".gitignore"
85
25
  - ".yardopts"
86
26
  - LICENSE
87
27
  - README.md
88
- - gems.rb
89
28
  - lib/tcp-client.rb
90
29
  - lib/tcp-client/address.rb
91
30
  - lib/tcp-client/configuration.rb
@@ -97,23 +36,13 @@ files:
97
36
  - lib/tcp-client/tcp_socket.rb
98
37
  - lib/tcp-client/version.rb
99
38
  - lib/tcp_client.rb
100
- - rakefile.rb
101
- - sample/google.rb
102
- - sample/google_ssl.rb
103
- - spec/helper.rb
104
- - spec/tcp-client/address_spec.rb
105
- - spec/tcp-client/configuration_spec.rb
106
- - spec/tcp-client/default_configuration_spec.rb
107
- - spec/tcp-client/version_spec.rb
108
- - spec/tcp_client_spec.rb
109
- - tcp-client.gemspec
110
39
  homepage: https://github.com/mblumtritt/tcp-client
111
40
  licenses:
112
41
  - BSD-3-Clause
113
42
  metadata:
114
43
  source_code_uri: https://github.com/mblumtritt/tcp-client
115
44
  bug_tracker_uri: https://github.com/mblumtritt/tcp-client/issues
116
- documentation_uri: https://rubydoc.info/github/mblumtritt/tcp-client
45
+ documentation_uri: https://rubydoc.info/gems/tcp-client
117
46
  post_install_message:
118
47
  rdoc_options: []
119
48
  require_paths:
@@ -132,11 +61,5 @@ requirements: []
132
61
  rubygems_version: 3.3.7
133
62
  signing_key:
134
63
  specification_version: 4
135
- summary: A TCP client implementation with working timeout support.
136
- test_files:
137
- - spec/helper.rb
138
- - spec/tcp-client/address_spec.rb
139
- - spec/tcp-client/configuration_spec.rb
140
- - spec/tcp-client/default_configuration_spec.rb
141
- - spec/tcp-client/version_spec.rb
142
- - spec/tcp_client_spec.rb
64
+ summary: Use your TCP connections with working timeout.
65
+ test_files: []
data/.gitignore DELETED
@@ -1,6 +0,0 @@
1
- tmp/
2
- pkg/
3
- local/
4
- doc/
5
- .yardoc/
6
- gems.locked
data/gems.rb DELETED
@@ -1,4 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source 'https://rubygems.org'
4
- gemspec
data/rakefile.rb DELETED
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rake/clean'
4
- require 'bundler/gem_tasks'
5
- require 'rspec/core/rake_task'
6
- require 'yard'
7
-
8
- $stdout.sync = $stderr.sync = true
9
-
10
- CLEAN << 'prj' << 'doc'
11
-
12
- CLOBBER << '.yardoc'
13
-
14
- task(:default) { exec('rake --tasks') }
15
-
16
- RSpec::Core::RakeTask.new { |task| task.ruby_opts = %w[-w] }
17
-
18
- YARD::Rake::YardocTask.new { |task| task.stats_options = %w[--list-undoc] }
data/sample/google.rb DELETED
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../lib/tcp-client'
4
-
5
- # global configuration.
6
- # - 0.5 seconds to connect the server
7
- # - 0.25 seconds to write a single data junk
8
- # - 0.25 seconds to read some bytes
9
- TCPClient.configure do |cfg|
10
- cfg.connect_timeout = 0.5
11
- cfg.write_timeout = 0.25
12
- cfg.read_timeout = 0.25
13
- end
14
-
15
- # request to Google:
16
- # - send a simple HTTP get request
17
- # - read 12 byte: "HTTP/1.1 " + 3 byte HTTP status code
18
- TCPClient.open('www.google.com:80') do |client|
19
- p client.write("GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n")
20
- p client.read(12)
21
- end
data/sample/google_ssl.rb DELETED
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../lib/tcp-client'
4
-
5
- # create a configuration:
6
- # - don't use internal buffering
7
- # - use TLS 1.2 or TLS 1.3
8
- cfg =
9
- TCPClient::Configuration.create(
10
- buffered: false,
11
- ssl_params: {
12
- min_version: :TLS1_2,
13
- max_version: :TLS1_3
14
- }
15
- )
16
-
17
- # request to Google.com:
18
- # - limit all network interactions to 1.5 seconds
19
- # - use the Configuration cfg
20
- # - send a simple HTTP get request
21
- # - read the returned message and headers
22
- response =
23
- TCPClient.with_deadline(1.5, 'www.google.com:443', cfg) do |client|
24
- client.write("GET / HTTP/1.1\r\nHost: www.google.com\r\n\r\n") #=> 40
25
- client.readline("\r\n\r\n") #=> see response
26
- end
27
-
28
- puts(response)
data/spec/helper.rb DELETED
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rspec/core'
4
- require_relative '../lib/tcp-client'
5
-
6
- $stdout.sync = $stderr.sync = true
7
-
8
- RSpec.configure do |config|
9
- config.disable_monkey_patching!
10
- config.warnings = true
11
- config.order = :random
12
- end