pipe_rpc 0.2.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
+ SHA1:
3
+ metadata.gz: 2ad289824f7ad565af6f419ddf007c4bd1745e37
4
+ data.tar.gz: d6511143979b1c2a998eb3072042a596d264307e
5
+ SHA512:
6
+ metadata.gz: a13574ab492318a87acb1c82b5f74eb6a7a4e28e4022106725ce3c405de8a56528d08d54493386b0e5d4fb5e5a025d4d77577c3065aa0cea4081529076380542
7
+ data.tar.gz: eeeb48e3f988525d562d66a5cd64d3f88d7df8edef572f10d4df391b00a53616e7b08ed9935ccd05923b7321ff60fac816f091f15c0d0dfc1c59cd22335077a6
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ test.rb
data/.rakeTasks ADDED
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Settings><!--This file was automatically generated by Ruby plugin.
3
+ You are allowed to:
4
+ 1. Remove rake task
5
+ 2. Add existing rake tasks
6
+ To add existing rake tasks automatically delete this file and reload the project.
7
+ --><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Build local_rpc-0.1.0.gem into the pkg directory" fullCmd="build" taksId="build" /><RakeTask description="Build and install local_rpc-0.1.0.gem into system gems" fullCmd="install" taksId="install" /><RakeTask description="Create tag v0.1.0 and build and push local_rpc-0.1.0.gem to Rubygems" fullCmd="release" taksId="release" /><RakeGroup description="" fullCmd="" taksId="release"><RakeTask description="" fullCmd="release:guard_clean" taksId="guard_clean" /><RakeTask description="" fullCmd="release:rubygem_push" taksId="rubygem_push" /><RakeTask description="" fullCmd="release:source_control_push" taksId="source_control_push" /></RakeGroup></RakeGroup></Settings>
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper.rb
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,59 @@
1
+ # PipeRpc
2
+
3
+ PipeRpc was designed so parent und child processes can call each other's methods. It uses a json protocol similar to JSON-RPC.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'pipe_rpc'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install pipe_rpc
20
+
21
+ ## Usage
22
+
23
+ ```ruby
24
+ require 'pipe_rpc'
25
+
26
+ request_read, request_write = IO.pipe
27
+ response_read, response_write = IO.pipe
28
+
29
+ pid = fork do
30
+ request_write.close
31
+ response_read.close
32
+
33
+ class Server
34
+ def add(a, b)
35
+ a + b
36
+ end
37
+ end
38
+
39
+ hub = PipeRpc::Hub.new(input: request_read, output: response_write)
40
+ hub.add_server(default: Server.new)
41
+
42
+ loop do
43
+ hub.handle_message # blocks until message available
44
+ end
45
+ end
46
+
47
+ begin
48
+ request_read.close
49
+ response_write.close
50
+
51
+ hub = PipeRpc::Hub.new(output: request_write, input: response_read)
52
+ client = hub.client_for(:default)
53
+
54
+ puts client.add(3, 5)
55
+ ensure
56
+ Process.kill 9, pid
57
+ Process.wait pid
58
+ end
59
+ ```
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/lib/hash.rb ADDED
@@ -0,0 +1,5 @@
1
+ class Hash
2
+ def symbolize_keys
3
+ Hash[self.map{ |k,v| [(k.to_sym rescue k), v] }]
4
+ end
5
+ end
@@ -0,0 +1,30 @@
1
+ module PipeRpc
2
+ class Client < BasicObject
3
+ def initialize(hub, args = {})
4
+ @hub = hub
5
+ @server = args.fetch(:server, :default).to_sym
6
+ end
7
+
8
+ def method_missing(method, *args)
9
+ backtrace = ::Kernel.respond_to?(:caller) ? ::Kernel.caller(1) : []
10
+
11
+ @hub.request(server: @server, method: method, arguments: args) do |result|
12
+ if result.is_a? ::StandardError
13
+ result.set_backtrace(result.backtrace.to_a + backtrace.to_a) if result.respond_to? :set_backtrace
14
+ ::Kernel.raise result
15
+ else
16
+ result
17
+ end
18
+ end
19
+ # Method won't return until we got a result because @hub.request starts a loop and blocks!
20
+ end
21
+
22
+ def to_s
23
+ "<Client:#{@server.to_s}>"
24
+ end
25
+
26
+ def is_a?(object)
27
+ object == Client
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,6 @@
1
+ module PipeRpc
2
+ class Error < RuntimeError; end
3
+ class InternalError < Error; end
4
+ class NoServerError < Error; end
5
+ class ReflectedError < Error; end
6
+ end
@@ -0,0 +1,77 @@
1
+ module PipeRpc
2
+ class ErrorResponse
3
+ def initialize(args = {})
4
+ @id = args.fetch(:id, nil)
5
+ error = args.fetch(:error)
6
+ @code = error.fetch(:code)
7
+ @message = msg_for(@code) || error.fetch(:message, 'Unknown error')
8
+ @data = error.fetch(:data, nil)
9
+ end
10
+
11
+ attr_reader :id, :code, :message, :data
12
+
13
+ def to_h
14
+ { id: id, error: { code: code, message: message, data: data } }
15
+ end
16
+
17
+ def native_error(request = nil)
18
+ @request = request
19
+ error_for(@code)
20
+ end
21
+
22
+ def result_for(*args)
23
+ native_error(*args)
24
+ end
25
+
26
+ private
27
+
28
+ def msg_for(code)
29
+ case code
30
+ when -32700 then 'Parse error'
31
+ when -32600 then 'Invalid Request'
32
+ when -32601 then 'Method not found'
33
+ when -32602 then 'Invalid arguments'
34
+ when -32603 then 'Internal error'
35
+ when -32604 then 'Server not found'
36
+ when -32605 then 'Reflected error'
37
+ else nil
38
+ end
39
+ end
40
+
41
+ def error_for(code)
42
+ case code
43
+ when -32601 then no_method_error
44
+ when -32602 then argument_error
45
+ when -32604 then no_server_error
46
+ when -32605 then reflected_error
47
+ else internal_error
48
+ end
49
+ end
50
+
51
+ def no_method_error
52
+ method = @data.fetch(:method)
53
+ args = @data.fetch(:args)
54
+ NoMethodError.new("undefined method `#{method}' for <Client:#{@request.server}>", method, args)
55
+ end
56
+
57
+ def argument_error
58
+ ArgumentError.new(@data.fetch(:message))
59
+ end
60
+
61
+ def no_server_error
62
+ NoServerError.new("undefined server `#{@request.server}'")
63
+ end
64
+
65
+ def internal_error
66
+ InternalError.new("#{@data[:message]}").tap do |error|
67
+ error.set_backtrace(@data[:backtrace]) if error.respond_to? :set_backtrace
68
+ end
69
+ end
70
+
71
+ def reflected_error
72
+ ReflectedError.new("#{@data[:message]}").tap do |error|
73
+ error.set_backtrace(@data[:backtrace]) if error.respond_to? :set_backtrace
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,57 @@
1
+ module PipeRpc
2
+ class Hub
3
+ class Message
4
+ def initialize(hub, message)
5
+ @hub = hub
6
+ @message = message
7
+ end
8
+
9
+ def notification?
10
+ @message.has_key? :method and not id?
11
+ end
12
+
13
+ def request?
14
+ @message.has_key? :method and id?
15
+ end
16
+
17
+ def response?
18
+ (result? or error_message?) and id?
19
+ end
20
+
21
+ def error?
22
+ error_message? and not id?
23
+ end
24
+
25
+ def handler
26
+ @handler ||= type.new(@message)
27
+ rescue => e
28
+ @hub.send_error(id: nil, code: -32600, data: { message: e.message })
29
+ nil
30
+ end
31
+
32
+ private
33
+
34
+ def result?
35
+ @message.has_key? :result
36
+ end
37
+
38
+ def error_message?
39
+ @message.has_key? :error
40
+ end
41
+
42
+ def type
43
+ if error_message?
44
+ ErrorResponse
45
+ elsif result?
46
+ ResultResponse
47
+ else
48
+ Request
49
+ end
50
+ end
51
+
52
+ def id?
53
+ not @message[:id].nil?
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,31 @@
1
+ module PipeRpc
2
+ class Hub
3
+ class Requester
4
+ def initialize(hub)
5
+ @hub = hub
6
+ @requests = {}
7
+ @uid = 0
8
+ end
9
+
10
+ def next_uid
11
+ @uid += 1
12
+ end
13
+
14
+ def notification(signature)
15
+ Request.new(signature)
16
+ end
17
+
18
+ def request(signature, &on_response)
19
+ request = Request.new(signature.merge(id: next_uid))
20
+ @requests[request.id] = { request: request, on_response: on_response }
21
+ request
22
+ end
23
+
24
+ def handle_response(response)
25
+ request = @requests.delete(response.id)
26
+ raise InternalError.new("no request for response(id: #{response.id})") unless request
27
+ request[:on_response].call response.result_for(request[:request])
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,90 @@
1
+ module PipeRpc
2
+ class Hub
3
+ class Responder
4
+ def initialize(hub)
5
+ @hub = hub
6
+ @servers = {}
7
+ end
8
+
9
+ def add_server(servers)
10
+ servers.each{ |name, server| @servers[name.to_sym] = server }
11
+ end
12
+
13
+ def rmv_server(server_name)
14
+ @servers.delete(server_name.to_sym)
15
+ end
16
+
17
+ def on_request(&on_request)
18
+ @on_request = on_request
19
+ end
20
+
21
+ def handle_notification(notification)
22
+ handle_request(notification) {}
23
+ end
24
+
25
+ def handle_request(request, &on_result)
26
+ id, server, method, args = request.id, @servers[request.server], request.method, request.arguments
27
+
28
+ unless server
29
+ @hub.send_error(id: id, code: -32604)
30
+ return
31
+ end
32
+
33
+ async = proc do |result|
34
+ on_result.call ResultResponse.new(id: id, result: result)
35
+ end
36
+
37
+ @on_request.call(server, method, args) if @on_request
38
+
39
+ # methods returning the async block as result state that they are asynchronous!
40
+ method_lineno = __LINE__+1
41
+ result = server.__send__(method, *args, &async)
42
+
43
+ # directly return result for synchronous calls
44
+ async.call(result) unless result == async
45
+
46
+ rescue NoMethodError => e
47
+ backtrace = e.backtrace.to_a
48
+ code = itself_caused_no_method_error?(backtrace, method_lineno) ? -32601 : -32603
49
+ @hub.send_error(id: id, code: code, data: { message: e.message, method: e.name,
50
+ args: e.args, backtrace: backtrace })
51
+
52
+ rescue ArgumentError => e
53
+ backtrace = e.backtrace.to_a
54
+ code = itself_caused_argument_error?(backtrace, method_lineno) ? -32602 : -32603
55
+ @hub.send_error(id: id, code: code, data: { message: e.message, backtrace: backtrace })
56
+
57
+ rescue InternalError => e # raised on the other side
58
+ backtrace = e.backtrace.to_a
59
+ @hub.send_error(id: id, code: -32605, data: { message: e.message, backtrace: backtrace })
60
+
61
+ rescue => e
62
+ backtrace = e.backtrace.to_a
63
+ @hub.send_error(id: id, code: -32603, data: { message: e.message, backtrace: backtrace })
64
+ end
65
+
66
+ private
67
+
68
+ def itself_caused_no_method_error?(backtrace, ref_lineno)
69
+ if Object.const_defined?(:MRUBY_VERSION)
70
+ !backtrace[0]
71
+ else
72
+ itself_caused_error?(backtrace[0], ref_lineno)
73
+ end
74
+ end
75
+
76
+ def itself_caused_argument_error?(backtrace, ref_lineno)
77
+ if Object.const_defined?(:MRUBY_VERSION)
78
+ !backtrace[0]
79
+ else
80
+ itself_caused_error?(backtrace[1], ref_lineno)
81
+ end
82
+ end
83
+
84
+ def itself_caused_error?(backtrace_loc, ref_lineno)
85
+ file, lineno, = backtrace_loc.split(':')
86
+ (file == __FILE__) and (lineno.to_i == ref_lineno)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,104 @@
1
+ module PipeRpc
2
+ class Hub
3
+ def initialize(args)
4
+ @channel = args[:input]
5
+ @socket = Socket.new(self, args)
6
+ @requester = Requester.new(self)
7
+ @responder = Responder.new(self)
8
+ @clients = {}
9
+ self.loop_iteration = nil
10
+ end
11
+
12
+ attr_reader :channel
13
+ attr_accessor :logger
14
+
15
+ def log(msg)
16
+ if logger == :reflect
17
+ notify(server: :reflect_logger, method: :log, arguments: [msg])
18
+ elsif logger.respond_to? :debug
19
+ logger.debug msg
20
+ elsif logger
21
+ logger.call msg
22
+ end
23
+ end
24
+
25
+ def add_server(servers)
26
+ @responder.add_server(servers)
27
+ end
28
+
29
+ def rmv_server(server_name)
30
+ @responder.rmv_server(server_name)
31
+ end
32
+
33
+ def on_incoming_request(&on_request)
34
+ @responder.on_request(&on_request)
35
+ end
36
+
37
+ def client_for(server_name)
38
+ @clients[server_name] ||= Client.new(self, server: server_name)
39
+ end
40
+
41
+ def loop_iteration=(proc)
42
+ @loop_iteration = proc
43
+ end
44
+
45
+ def on_sent(&on_sent)
46
+ @socket.on_write(&on_sent)
47
+ end
48
+
49
+ def on_received(&on_received)
50
+ @socket.on_read(&on_received)
51
+ end
52
+
53
+ def notify(signature)
54
+ @socket.write @requester.notification(signature)
55
+ end
56
+
57
+ def request(signature, &on_result)
58
+ result = nil
59
+ result_ready = false
60
+
61
+ request = @requester.request(signature) do |*response|
62
+ result = on_result.call(*response)
63
+ result_ready = true
64
+ end
65
+ @socket.write request
66
+
67
+ loop do
68
+ return result if result_ready
69
+ @loop_iteration ? @loop_iteration.call : handle_message
70
+ end
71
+ end
72
+
73
+ def send_error(error = {})
74
+ @socket.write ErrorResponse.new(id: error.delete(:id), error: error)
75
+ end
76
+
77
+ def handle_message
78
+ message = next_message # blocks
79
+
80
+ return unless message
81
+
82
+ if message.notification?
83
+ @responder.handle_notification(message.handler)
84
+ elsif message.request?
85
+ @responder.handle_request(message.handler) { |response| @socket.write response }
86
+ elsif message.response?
87
+ @requester.handle_response(message.handler)
88
+ elsif message.error?
89
+ raise message.handler.native_error
90
+ else
91
+ send_error(id: nil, code: -32600, data: { message: 'no request, result or error' })
92
+ end
93
+ end
94
+
95
+ private
96
+
97
+ def next_message
98
+ Message.new(self, @socket.read) # blocks
99
+ rescue => e
100
+ send_error(id: nil, code: -32700, data: { message: e.message })
101
+ nil
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,16 @@
1
+ module PipeRpc
2
+ class Request
3
+ def initialize(args)
4
+ @server = args.fetch(:server, :default).to_sym
5
+ @method = args.fetch(:method).to_sym
6
+ @arguments = args.fetch(:arguments, [])
7
+ @id = args.fetch(:id, nil)
8
+ end
9
+
10
+ attr_reader :server, :method, :arguments, :id
11
+
12
+ def to_h
13
+ { server: server, method: method, arguments: arguments, id: id }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,32 @@
1
+ module PipeRpc
2
+ class ResultResponse
3
+ def initialize(args = {})
4
+ @result = sanitize(args.fetch(:result))
5
+ @id = args.fetch(:id)
6
+ end
7
+
8
+ attr_reader :result, :id
9
+
10
+ def result_for(request)
11
+ result
12
+ end
13
+
14
+ def to_h
15
+ { id: id, result: result }
16
+ end
17
+
18
+ private
19
+
20
+ def sanitize(result)
21
+ if true == result or false == result or nil == result or result.is_a?(String) or result.is_a?(Numeric)
22
+ result
23
+ elsif result.is_a?(Array)
24
+ result.map{ |v| sanitize(v) }
25
+ elsif result.is_a?(Hash)
26
+ Hash[result.map{ |k,v| [sanitize(k), sanitize(v)] }]
27
+ else
28
+ result.to_s
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,45 @@
1
+ module PipeRpc
2
+ class Socket
3
+ def initialize(hub, args = {})
4
+ @hub = hub
5
+ @input = args.fetch(:input)
6
+ @output = args.fetch(:output)
7
+ on_write{}
8
+ on_read{}
9
+ end
10
+
11
+ def read
12
+ symbolize_message_keys(JSON.load(@input.gets)).tap do |message|
13
+ next if message[:server] == 'reflect_logger'
14
+ @hub.log "received: #{message.inspect}"
15
+ @on_read.call(message)
16
+ end
17
+ end
18
+
19
+ def write(obj)
20
+ raise InternalError.new('Output pipe broke') if @output.closed?
21
+ @output.puts(JSON.dump(obj.to_h.tap do |message|
22
+ next if @hub.logger == :reflect
23
+ @hub.log "sent: #{message.inspect}"
24
+ @on_write.call(message)
25
+ end))
26
+ end
27
+
28
+ def on_write(&on_write)
29
+ @on_write = on_write || proc{}
30
+ end
31
+
32
+ def on_read(&on_read)
33
+ @on_read = on_read || proc{}
34
+ end
35
+
36
+ private
37
+
38
+ def symbolize_message_keys(message)
39
+ hash = message.symbolize_keys
40
+ hash[:error] = hash[:error].symbolize_keys if hash[:error]
41
+ hash[:error][:data] = hash[:error][:data].symbolize_keys if hash[:error] and hash[:error][:data]
42
+ hash
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,3 @@
1
+ module PipeRpc
2
+ VERSION = "0.2.0"
3
+ end
data/lib/pipe_rpc.rb ADDED
@@ -0,0 +1,16 @@
1
+ module PipeRpc
2
+ end
3
+
4
+ require 'json'
5
+ require_relative 'hash'
6
+ require_relative "pipe_rpc/version"
7
+ require_relative "pipe_rpc/error"
8
+ require_relative "pipe_rpc/request"
9
+ require_relative "pipe_rpc/result_response"
10
+ require_relative "pipe_rpc/error_response"
11
+ require_relative "pipe_rpc/socket"
12
+ require_relative "pipe_rpc/client"
13
+ require_relative "pipe_rpc/hub"
14
+ require_relative "pipe_rpc/hub/message"
15
+ require_relative "pipe_rpc/hub/requester"
16
+ require_relative "pipe_rpc/hub/responder"
data/pipe_rpc.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pipe_rpc/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "pipe_rpc"
8
+ spec.version = PipeRpc::VERSION
9
+ spec.authors = ["Christopher Aue"]
10
+ spec.email = ["mail@christopheraue.net"]
11
+
12
+ spec.summary = %q{RPC between parent and child process over pipes}
13
+ spec.description = %q{PipeRpc was designed so parent und child processes can call each other's
14
+ methods. It uses a json protocol similar to JSON-RPC.}
15
+ spec.homepage = "https://github.com/christopheraue/ruby-pipe_rpc"
16
+ spec.license = "MIT"
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_runtime_dependency "json"
23
+ spec.add_development_dependency "bundler", "~> 1.8"
24
+ spec.add_development_dependency "rspec", "~> 3.4"
25
+ spec.add_development_dependency "rspec-its"
26
+ spec.add_development_dependency "rspec-mocks-matchers-send_message", "~> 0.2"
27
+ end
metadata ADDED
@@ -0,0 +1,137 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pipe_rpc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Christopher Aue
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
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: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.8'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.4'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-its
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'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-mocks-matchers-send_message
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.2'
83
+ description: |-
84
+ PipeRpc was designed so parent und child processes can call each other's
85
+ methods. It uses a json protocol similar to JSON-RPC.
86
+ email:
87
+ - mail@christopheraue.net
88
+ executables: []
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - ".gitignore"
93
+ - ".rakeTasks"
94
+ - ".rspec"
95
+ - ".travis.yml"
96
+ - Gemfile
97
+ - README.md
98
+ - Rakefile
99
+ - lib/hash.rb
100
+ - lib/pipe_rpc.rb
101
+ - lib/pipe_rpc/client.rb
102
+ - lib/pipe_rpc/error.rb
103
+ - lib/pipe_rpc/error_response.rb
104
+ - lib/pipe_rpc/hub.rb
105
+ - lib/pipe_rpc/hub/message.rb
106
+ - lib/pipe_rpc/hub/requester.rb
107
+ - lib/pipe_rpc/hub/responder.rb
108
+ - lib/pipe_rpc/request.rb
109
+ - lib/pipe_rpc/result_response.rb
110
+ - lib/pipe_rpc/socket.rb
111
+ - lib/pipe_rpc/version.rb
112
+ - pipe_rpc.gemspec
113
+ homepage: https://github.com/christopheraue/ruby-pipe_rpc
114
+ licenses:
115
+ - MIT
116
+ metadata: {}
117
+ post_install_message:
118
+ rdoc_options: []
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ requirements: []
132
+ rubyforge_project:
133
+ rubygems_version: 2.4.5.1
134
+ signing_key:
135
+ specification_version: 4
136
+ summary: RPC between parent and child process over pipes
137
+ test_files: []