io_request 1.0.0

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