io_request 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d6ba3ef4cb967a230cfb350a7413cee8868a2817f5451134105c7ba075470427
4
+ data.tar.gz: 1438ae77d9f2db624bbf8596d2b4acbf793aa1826bcc9a6e0f83dfe8fde3e541
5
+ SHA512:
6
+ metadata.gz: e1cc15e03f5489653ec07ce7d7424992ee259b508124972f84fe8c2f10bf08465a59ebebd25dc30cba5be8012c583c2028b4c22332882e13e575903c0898e7af
7
+ data.tar.gz: a648b296f3b12c90205253bd40ce906b12a5638b892113bfdcf54deedaed8a41d5262c5f4937edc28509de862ce52c91429f450c40a8b97c60acdcf8afdec651
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.5.5
7
+ before_install: gem install bundler -v 2.0.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in io_request.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,28 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ io_request (1.0.0)
5
+ json (~> 2.0)
6
+ logger (~> 1.4)
7
+ timeout-extensions (~> 0.1.1)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ json (2.2.0)
13
+ logger (1.4.1)
14
+ minitest (5.13.0)
15
+ rake (10.5.0)
16
+ timeout-extensions (0.1.1)
17
+
18
+ PLATFORMS
19
+ x64-mingw32
20
+
21
+ DEPENDENCIES
22
+ bundler (~> 2.0)
23
+ io_request!
24
+ minitest (~> 5.0)
25
+ rake (~> 10.0)
26
+
27
+ BUNDLED WITH
28
+ 2.0.2
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Fizvlad
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # IORequest
2
+
3
+ Small gem to create JSON request/response type of connection over IO object
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'io_request'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install io_request
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Development
26
+
27
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
28
+
29
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
30
+
31
+ ## Contributing
32
+
33
+ Bug reports and pull requests are welcome on GitHub at https://github.com/fizvlad/io-request-rb.
34
+
35
+ ## License
36
+
37
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "io_request"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,37 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "io_request/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "io_request"
7
+ spec.version = IORequest::VERSION
8
+ spec.authors = ["Fizvlad"]
9
+ spec.email = ["fizvlad@mail.ru"]
10
+
11
+ spec.summary = "Small gem to create JSON request/response type of connection over IO object"
12
+ spec.homepage = "https://github.com/fizvlad/io-request-rb"
13
+ spec.license = "MIT"
14
+
15
+ spec.required_ruby_version = ">=2.3.1"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/fizvlad/io-request-rb"
19
+ spec.metadata["changelog_uri"] = "https://github.com/fizvlad/io-request-rb/releases"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_development_dependency "bundler", "~> 2.0"
31
+ spec.add_development_dependency "rake", "~> 10.0"
32
+ spec.add_development_dependency "minitest", "~> 5.0"
33
+
34
+ spec.add_runtime_dependency "logger", "~>1.4"
35
+ spec.add_runtime_dependency "timeout-extensions", "~>0.1.1"
36
+ spec.add_runtime_dependency "json", "~>2.0"
37
+ end
@@ -0,0 +1,183 @@
1
+ require "base64"
2
+ require "timeout"
3
+ require "json"
4
+
5
+ module IORequest
6
+ # Connection client.
7
+ class Client
8
+ include Utility::WithProgName
9
+ include Utility::MultiThread
10
+
11
+ # IO-like object provided at initialization.
12
+ attr_reader :io
13
+
14
+ # Initialize new client over IO.
15
+ #
16
+ # @option options [:gets] read IO to read from.
17
+ # @option options [:puts] write IO to write to.
18
+ def initialize(read: nil, write: nil)
19
+ @io_r = read
20
+ @io_w = write
21
+
22
+ @mutex = Mutex.new
23
+ @responders = [] # Array of pairs [Subhash, Block]
24
+ @out_requests = {} # Request => Proc
25
+
26
+ @receive_thread = Thread.new { receive_loop }
27
+ IORequest.debug("New IORequest client initialized", prog_name)
28
+ end
29
+
30
+ # Send request.
31
+ #
32
+ # Optional block can be provided. It will be called when response received.
33
+ #
34
+ # @param data [Hash] data to send with request.
35
+ #
36
+ # @option options [Boolean] sync whether to join request after sending.
37
+ # @option options [Integer, Float] timeout timeout for {Request#join}.
38
+ #
39
+ # @yieldparam request [Response] response for request.
40
+ #
41
+ # @return [Request]
42
+ def request(data: {}, sync: false, timeout: nil, &block)
43
+ req = Request.new(data)
44
+ @out_requests[req] = block
45
+ send(req.to_hash)
46
+ req.join(timeout) if sync
47
+ req
48
+ end
49
+
50
+ # Setup block for answering incoming requests.
51
+ #
52
+ # @param subdata [Hash] provided block will be called only if received data
53
+ # includes this hash.
54
+ #
55
+ # @yieldparam request [Request] incoming request.
56
+ # @yieldreturn [Hash] data to be sent in response.
57
+ #
58
+ # @return [nil]
59
+ def respond(subdata = {}, &block)
60
+ @responders << [subdata, block]
61
+ nil
62
+ end
63
+
64
+ private
65
+
66
+ # Starts receiving loop and freezes thread.
67
+ def receive_loop
68
+ loop do
69
+ h = receive(nil)
70
+ break if h.nil?
71
+ case h[:type]
72
+ when "request"
73
+ handle_in_request(Request.from_hash h)
74
+ when "response"
75
+ handle_in_response(Response.from_hash h)
76
+ else
77
+ IORequest.warn("Unknown message type: #{h[:type].inspect}", prog_name)
78
+ end
79
+ end
80
+ IORequest.debug("Receive loop exited", prog_name)
81
+ end
82
+ # Handle incoming request.
83
+ def handle_in_request(req)
84
+ IORequest.debug("Handling request ##{req.id}", prog_name)
85
+ in_thread do
86
+ responder = find_responder(req)
87
+ data = nil
88
+ begin
89
+ data = responder.call(req) if responder
90
+ rescue Exception => e
91
+ IORequest.warn("Provided block raised exception:\n#{e.full_message}", prog_name)
92
+ end
93
+ data = {} unless data.is_a?(Hash)
94
+ res = Response.new(data, req)
95
+ send(res.to_hash)
96
+ end
97
+ nil
98
+ end
99
+ # Handle incoming response.
100
+ def handle_in_response(res)
101
+ req_id = res.request.to_i
102
+ req = @out_requests.keys.find { |r| r.id == req_id }
103
+ unless req
104
+ IORequest.warn("Request ##{req_id} not found", prog_name)
105
+ return
106
+ end
107
+ IORequest.debug("Request ##{req_id} response received", prog_name)
108
+ req.response = res
109
+ # If block is not provided it's totally ok
110
+ block = @out_requests.delete(req)
111
+ if block
112
+ in_thread do
113
+ begin
114
+ block.call(res)
115
+ rescue Exception => e
116
+ IORequest.warn("Provided block raised exception:\n#{e.full_message}", prog_name)
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ # find responder for provided request.
123
+ def find_responder(req)
124
+ @responders.each do |subdata, block|
125
+ break block if req.data.contains? subdata
126
+ end
127
+ end
128
+
129
+ # Send data.
130
+ #
131
+ # @param [Hash]
132
+ def send(data)
133
+ send_raw(encode(data_to_string data))
134
+ end
135
+
136
+ # Receive data.
137
+ #
138
+ # @param timeout [Integer, Float, nil] timeout size or +nil+ if no timeout required.
139
+ #
140
+ # @return [Hash, nil] hash or +nil+ if timed out or IO was closed.
141
+ def receive(timeout)
142
+ str = Timeout::timeout(timeout) do
143
+ receive_raw
144
+ end
145
+ return nil if str.nil?
146
+ string_to_data(decode(str))
147
+ rescue Timeout::Error
148
+ nil
149
+ rescue IOError
150
+ nil
151
+ rescue Exception => e
152
+ IORequest.warn "Exception of #{e.class} encountered while trying to receive message. Suggesting IO was closed. Full trace: #{e.full_message}", prog_name
153
+ nil
154
+ end
155
+
156
+ # Send string.
157
+ def send_raw(str)
158
+ @io_w.puts str
159
+ end
160
+ # Receive string.
161
+ def receive_raw
162
+ @io_r.gets&.chomp
163
+ end
164
+
165
+ # Encode string
166
+ def encode(str)
167
+ Base64::strict_encode64 str
168
+ end
169
+ # Decode string
170
+ def decode(str)
171
+ Base64::strict_decode64 str
172
+ end
173
+
174
+ # Turn data into string
175
+ def data_to_string(data)
176
+ JSON.generate(data)
177
+ end
178
+ # Turn string into data
179
+ def string_to_data(str)
180
+ JSON.parse(str).symbolize_keys!
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,49 @@
1
+ require "logger"
2
+
3
+ module IORequest
4
+ # @!group Logger
5
+
6
+ # Default logger.
7
+ @@logger = Logger.new($LOG_FILE || STDOUT,
8
+ formatter: Proc.new do |severity, datetime, progname, msg|
9
+ "[#{datetime}] #{severity} - #{progname}:\t #{msg}\n"
10
+ end
11
+ )
12
+ @@logger.level = $DEBUG ? Logger::DEBUG : Logger::INFO
13
+
14
+ # Setup new logger.
15
+ #
16
+ # @param logger [Logger, nil]
17
+ def self.logger=(logger)
18
+ @@logger = logger
19
+ end
20
+
21
+ # Access current logger.
22
+ #
23
+ # @return [Logger, nil]
24
+ def self.logger
25
+ @@logger
26
+ end
27
+
28
+ # Log message.
29
+ def self.log(severity, message = nil, progname = nil)
30
+ @@logger.log(severity, message, progname) if @@logger
31
+ end
32
+
33
+ # Log warning message.
34
+ def self.warn(message = nil, progname = nil)
35
+ @@logger.log(Logger::WARN, message, progname)
36
+ end
37
+
38
+ # Log info message.
39
+ def self.info(message = nil, progname = nil)
40
+ @@logger.log(Logger::INFO, message, progname)
41
+ end
42
+
43
+ # Log debug message.
44
+ def self.debug(message = nil, progname = nil)
45
+ @@logger.log(Logger::DEBUG, message, progname)
46
+ end
47
+
48
+ # @!endgroup
49
+ end
@@ -0,0 +1,112 @@
1
+ module IORequest
2
+ # Message to other side of IO.
3
+ class Message
4
+ # @return [Integer] ID of message.
5
+ attr_reader :id
6
+ alias_method :to_i, :id
7
+
8
+ # @return [Hash] stored data.
9
+ attr_reader :data
10
+
11
+ # Initialize new message.
12
+ #
13
+ # @param data [Hash]
14
+ # @param id [Integer, nil] if +nil+ provided {Message.generate_id} will be
15
+ # used to generate random id.
16
+ def initialize(data, id = nil)
17
+ @id = id || Message.generate_id
18
+ @data = data
19
+ end
20
+
21
+ # @return [String] human-readable form.
22
+ def to_s
23
+ "#{self.class.name}##{@id}: #{@data.inspect}"
24
+ end
25
+
26
+ # @return [Integer] random numerical ID based on current time and random salt.
27
+ def self.generate_id
28
+ ((rand(999) + 1) * Time.now.to_f * 1000).to_i % 2**32
29
+ end
30
+ end
31
+
32
+ # Request for server or client.
33
+ class Request < Message
34
+ # Amount of time to sleep before checking whether responded.
35
+ JOIN_SLEEP_TIME = 0.5
36
+
37
+ # @return [Integer, Response, nil] ID of response or response itself for this message.
38
+ attr_reader :response
39
+
40
+ # @!visibility private
41
+ attr_writer :response
42
+
43
+ # Initialize new request.
44
+ #
45
+ # @param data [Hash]
46
+ # @param response [Integer, Response, nil]
47
+ # @param id [Integer, nil]
48
+ def initialize(data, response = nil, id = nil)
49
+ @response = response
50
+ super(data, id)
51
+ end
52
+
53
+ # @return [String] human readable form.
54
+ def to_s
55
+ "#{super.to_s}; #{@response ? "Response ID: #{@response.to_i}" : "Not responded"}"
56
+ end
57
+
58
+ # Freezes thread until request is responded or until timeout expends.
59
+ #
60
+ # @param timeout [Integer, Float, nil] timeout size or +nil+ if no timeout.
61
+ #
62
+ # @return [Integer] amount of time passed
63
+ def join(timeout = nil)
64
+ time_passed = 0
65
+ while @response.nil? && (timeout.nil? || time_passed < timeout)
66
+ time_passed += (sleep JOIN_SLEEP_TIME)
67
+ end
68
+ time_passed
69
+ end
70
+
71
+ # Save into hash.
72
+ def to_hash
73
+ { type: "request", data: @data, id: @id, response: @response.to_i }
74
+ end
75
+
76
+ # Initialize new request from hash obtained with {Request#to_hash}.
77
+ def self.from_hash(hash)
78
+ Request.new(hash[:data], hash[:response], hash[:id])
79
+ end
80
+ end
81
+
82
+ # Response to some request.
83
+ class Response < Message
84
+ # @return [Integer, Request] ID of initial request or request itself.
85
+ attr_reader :request
86
+
87
+ # Initialize new response.
88
+ #
89
+ # @param data [Hash]
90
+ # @param request [Integer, Request]
91
+ # @param id [Integer, nil]
92
+ def initialize(data, request, id = nil)
93
+ @request = request
94
+ super(data, id)
95
+ end
96
+
97
+ # @return [String] human readable form.
98
+ def to_s
99
+ "#{super.to_s}; Initial request ID: #{@request.to_i}"
100
+ end
101
+
102
+ # Save into hash.
103
+ def to_hash
104
+ { type: "response", data: @data, id: @id, request: @request.to_i }
105
+ end
106
+
107
+ # Initialize new request from hash obtained with {Response#to_hash}.
108
+ def self.from_hash(hash)
109
+ Response.new(hash[:data], hash[:request], hash[:id])
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,99 @@
1
+ module IORequest
2
+ # Utility methods.
3
+ module Utility
4
+ # Adds special method to identify object in log files.
5
+ module WithProgName
6
+ ##
7
+ # Identifies object and thread it runs in.
8
+ def prog_name
9
+ self_class = self.class
10
+ "#{self_class.name}##{object_id} in Thread##{Thread.current.object_id}"
11
+ end
12
+ end
13
+
14
+ # Adds some methods to spawn new threads and join them.
15
+ #
16
+ # @note This module creates instance variables with prefix +@_MultiThread_+.
17
+ module MultiThread
18
+ private
19
+
20
+ # @return [Array<Thread>] array of running threads
21
+ def running_threads
22
+ @_MultiThread_threads ||= []
23
+ end
24
+
25
+ # Runs block with provided arguments forwarded as arguments in separate thread.
26
+ #
27
+ # @return [Thread]
28
+ def in_thread(*args, &block)
29
+ @_MultiThread_threads ||= []
30
+ @_MultiThread_mutex ||= Mutex.new
31
+ # Synchronizing addition/deletion of new threads. That's important
32
+ @_MultiThread_mutex.synchronize do
33
+ new_thread = Thread.new(*args) do |*in_args|
34
+ begin
35
+ block.call(*in_args)
36
+ ensure
37
+ @_MultiThread_mutex.synchronize do
38
+ @_MultiThread_threads.delete(Thread.current)
39
+ end
40
+ end
41
+ end
42
+ @_MultiThread_threads << new_thread
43
+ new_thread
44
+ end
45
+ end
46
+
47
+ # For each running thread.
48
+ def each_thread(&block)
49
+ @_MultiThread_threads ||= []
50
+
51
+ @_MultiThread_threads.each(&block)
52
+ end
53
+
54
+ # Kills each thread.
55
+ def kill_threads
56
+ each_thread(&:kill)
57
+ each_thread(&:join)
58
+ end
59
+
60
+ # Joins each thread.
61
+ def join_threads
62
+ each_thread(&:join)
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ # Extending Hash class.
69
+ class Hash
70
+ # Use this on JSON objects to turn all the +String+ keys of hash to symbols.
71
+ #
72
+ # @param depth [Integer] maximum amount of hashes to handle. This is just a
73
+ # simple way to protect from infinite loop.
74
+ #
75
+ # @return [self]
76
+ def symbolize_keys!(depth = 1000)
77
+ queue = [self]
78
+ count = 0
79
+ while h = queue.shift
80
+ h.transform_keys! { |key| key.is_a?(String) ? key.to_sym : key }
81
+ h.each_value { |v| queue.push(v) if v.is_a?(Hash) }
82
+ count += 1
83
+ break if count >= depth
84
+ end
85
+ self
86
+ end
87
+
88
+ # Whether provided hash is included into this one.
89
+ #
90
+ # @param other [Hash]
91
+ #
92
+ # @return [Boolean]
93
+ def contains?(other)
94
+ other.keys.all? do |key|
95
+ other[key] == self[key]
96
+ end
97
+ end
98
+ end
99
+
@@ -0,0 +1,4 @@
1
+ module IORequest
2
+ # Gem version.
3
+ VERSION = "1.0.0"
4
+ end
data/lib/io_request.rb ADDED
@@ -0,0 +1,8 @@
1
+ require_relative "io_request/version"
2
+ require_relative "io_request/utility"
3
+ require_relative "io_request/logging"
4
+ require_relative "io_request/message"
5
+ require_relative "io_request/client"
6
+
7
+ # Main module.
8
+ module IORequest; end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: io_request
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Fizvlad
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-11-13 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: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.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: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: logger
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.4'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: timeout-extensions
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.1.1
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.1.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: json
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.0'
97
+ description:
98
+ email:
99
+ - fizvlad@mail.ru
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".travis.yml"
106
+ - Gemfile
107
+ - Gemfile.lock
108
+ - LICENSE.txt
109
+ - README.md
110
+ - Rakefile
111
+ - bin/console
112
+ - io_request.gemspec
113
+ - lib/io_request.rb
114
+ - lib/io_request/client.rb
115
+ - lib/io_request/logging.rb
116
+ - lib/io_request/message.rb
117
+ - lib/io_request/utility.rb
118
+ - lib/io_request/version.rb
119
+ homepage: https://github.com/fizvlad/io-request-rb
120
+ licenses:
121
+ - MIT
122
+ metadata:
123
+ homepage_uri: https://github.com/fizvlad/io-request-rb
124
+ source_code_uri: https://github.com/fizvlad/io-request-rb
125
+ changelog_uri: https://github.com/fizvlad/io-request-rb/releases
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: 2.3.1
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubygems_version: 3.0.4
142
+ signing_key:
143
+ specification_version: 4
144
+ summary: Small gem to create JSON request/response type of connection over IO object
145
+ test_files: []