arpie 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +15 -0
- data/README +89 -0
- data/Rakefile +111 -0
- data/lib/arpie.rb +4 -0
- data/lib/arpie/endpoint.rb +94 -0
- data/lib/arpie/protocol.rb +51 -0
- data/lib/arpie/proxy.rb +46 -0
- data/lib/arpie/transport.rb +37 -0
- data/spec/rcov.opts +0 -0
- data/spec/spec.opts +0 -0
- data/tools/benchmark.rb +57 -0
- metadata +73 -0
data/COPYING
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Copyright (C) 2008 Bernhard Stoeckner <elven@swordcoast.net> and contributors
|
2
|
+
|
3
|
+
This program is free software; you can redistribute it and/or modify
|
4
|
+
it under the terms of the GNU General Public License as published by
|
5
|
+
the Free Software Foundation; either version 2 of the License, or
|
6
|
+
(at your option) any later version.
|
7
|
+
|
8
|
+
This program is distributed in the hope that it will be useful,
|
9
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
GNU General Public License for more details.
|
12
|
+
|
13
|
+
You should have received a copy of the GNU General Public License along
|
14
|
+
with this program; if not, write to the Free Software Foundation, Inc.,
|
15
|
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
data/README
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
= What's this?
|
2
|
+
|
3
|
+
Arpie is a end-to-end framework for sending synchronous message-and-answer
|
4
|
+
pairs, and serves as the basis for a RPC framework, handling a variety of protocols,
|
5
|
+
including a generic Marshal proof of concept; writing your own Protocol is quite simple.
|
6
|
+
|
7
|
+
* It uses ruby threads on the server side, one per connection.
|
8
|
+
* The client is single-threaded.
|
9
|
+
|
10
|
+
== Source Code
|
11
|
+
|
12
|
+
Source code is in git[http://git.swordcoast.net/?p=lib/ruby/arpie.git;a=summary].
|
13
|
+
|
14
|
+
You can contact me via email at elven@swordcoast.net.
|
15
|
+
|
16
|
+
|
17
|
+
== Simple, contrived example: A string reverse server
|
18
|
+
|
19
|
+
require 'rubygems'
|
20
|
+
require 'arpie'
|
21
|
+
require 'socket'
|
22
|
+
|
23
|
+
server = TCPServer.new(51210)
|
24
|
+
|
25
|
+
e = Arpie::Endpoint.new(Arpie::MarshalProtocol.new)
|
26
|
+
|
27
|
+
e.handle do |ep, msg|
|
28
|
+
msg.reverse
|
29
|
+
end
|
30
|
+
|
31
|
+
e.accept do
|
32
|
+
server.accept
|
33
|
+
end
|
34
|
+
|
35
|
+
c = Arpie::Transport.new(Arpie::MarshalProtocol.new)
|
36
|
+
c.connect do |transport|
|
37
|
+
TCPSocket.new("127.0.0.1", 51210)
|
38
|
+
end
|
39
|
+
|
40
|
+
puts c.request "hi"
|
41
|
+
# => "ih"
|
42
|
+
|
43
|
+
== Advanced, but still simple example: Using Proxy to access remote objects
|
44
|
+
|
45
|
+
require 'rubygems'
|
46
|
+
require 'arpie'
|
47
|
+
require 'socket'
|
48
|
+
|
49
|
+
class MyHandler
|
50
|
+
def reverse str
|
51
|
+
str.reverse
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
server = TCPServer.new(51210)
|
56
|
+
|
57
|
+
e = Arpie::ProxyEndpoint.new(Arpie::MarshalProtocol.new)
|
58
|
+
|
59
|
+
e.handle MyHandler.new
|
60
|
+
|
61
|
+
e.accept do
|
62
|
+
server.accept
|
63
|
+
end
|
64
|
+
|
65
|
+
c = Arpie::Transport.new(Arpie::MarshalProtocol.new)
|
66
|
+
c.connect do |transport|
|
67
|
+
TCPSocket.new("127.0.0.1", 51210)
|
68
|
+
end
|
69
|
+
p = Arpie::Proxy.new(c)
|
70
|
+
|
71
|
+
puts p.reverse "hi"
|
72
|
+
# => "ih"
|
73
|
+
|
74
|
+
== Benchmarks
|
75
|
+
|
76
|
+
There is a benchmark script included in the git repository (and in the gem
|
77
|
+
under tools/). A sample output follows; your milage may vary.
|
78
|
+
|
79
|
+
user system total real
|
80
|
+
|
81
|
+
native DRb
|
82
|
+
1 0.000000 0.000000 0.000000 ( 0.000167)
|
83
|
+
1000 0.120000 0.010000 0.130000 ( 0.121834)
|
84
|
+
|
85
|
+
ruby xmlrpc/server - too slow to benchmark
|
86
|
+
|
87
|
+
Arpie: proxied MarshalProtocol
|
88
|
+
1 0.000000 0.000000 0.000000 ( 0.000617)
|
89
|
+
1000 0.100000 0.020000 0.120000 ( 0.114573)
|
data/Rakefile
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
require "rake"
|
2
|
+
require "rake/clean"
|
3
|
+
require "rake/gempackagetask"
|
4
|
+
require "rake/rdoctask"
|
5
|
+
require "fileutils"
|
6
|
+
include FileUtils
|
7
|
+
|
8
|
+
##############################################################################
|
9
|
+
# Configuration
|
10
|
+
##############################################################################
|
11
|
+
NAME = "arpie"
|
12
|
+
VERS = "0.0.1"
|
13
|
+
CLEAN.include ["**/.*.sw?", "pkg", ".config", "rdoc", "coverage"]
|
14
|
+
RDOC_OPTS = ["--quiet", "--line-numbers", "--inline-source", '--title', \
|
15
|
+
"#{NAME}: A high-performing layered RPC framework. Simple to use, simple to extend.", \
|
16
|
+
'--main', 'README']
|
17
|
+
|
18
|
+
DOCS = ["README", "COPYING"]
|
19
|
+
|
20
|
+
Rake::RDocTask.new do |rdoc|
|
21
|
+
rdoc.rdoc_dir = "rdoc"
|
22
|
+
rdoc.options += RDOC_OPTS
|
23
|
+
rdoc.rdoc_files.add DOCS + ["doc/*.rdoc", "lib/**/*.rb"]
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "Packages up #{NAME}"
|
27
|
+
task :package => [:clean]
|
28
|
+
|
29
|
+
spec = Gem::Specification.new do |s|
|
30
|
+
s.name = NAME
|
31
|
+
s.rubyforge_project = "#{NAME}"
|
32
|
+
s.version = VERS
|
33
|
+
s.platform = Gem::Platform::RUBY
|
34
|
+
s.has_rdoc = true
|
35
|
+
s.extra_rdoc_files = DOCS + Dir["doc/*.rdoc"]
|
36
|
+
s.rdoc_options += RDOC_OPTS + ["--exclude", "^(examples|extras)\/"]
|
37
|
+
s.summary = "a synchronous RPC library based on google protobuf"
|
38
|
+
s.description = s.summary
|
39
|
+
s.author = "Bernhard Stoeckner"
|
40
|
+
s.email = "elven@swordcoast.net"
|
41
|
+
s.homepage = "http://#{NAME}.elv.es"
|
42
|
+
s.executables = []
|
43
|
+
s.required_ruby_version = ">= 1.8.4"
|
44
|
+
s.files = %w(COPYING README Rakefile) + Dir.glob("{bin,doc,spec,lib,tools,scripts,data}/**/*")
|
45
|
+
s.require_path = "lib"
|
46
|
+
s.bindir = "bin"
|
47
|
+
end
|
48
|
+
|
49
|
+
Rake::GemPackageTask.new(spec) do |p|
|
50
|
+
p.need_tar = true
|
51
|
+
p.gem_spec = spec
|
52
|
+
end
|
53
|
+
|
54
|
+
desc "Install #{NAME} gem"
|
55
|
+
task :install do
|
56
|
+
sh %{rake package}
|
57
|
+
sh %{sudo gem1.8 install pkg/#{NAME}-#{VERS}}
|
58
|
+
end
|
59
|
+
|
60
|
+
desc "Regenerate proto classes"
|
61
|
+
task :protoc do
|
62
|
+
sh %{rprotoc --out=lib/arpie arpie.proto}
|
63
|
+
end
|
64
|
+
|
65
|
+
desc "Install #{NAME} gem without docs"
|
66
|
+
task :install_no_docs do
|
67
|
+
sh %{rake package}
|
68
|
+
sh %{sudo gem1.8 install pkg/#{NAME}-#{VERS} --no-rdoc --no-ri}
|
69
|
+
end
|
70
|
+
|
71
|
+
desc "Uninstall #{NAME} gem"
|
72
|
+
task :uninstall => [:clean] do
|
73
|
+
sh %{sudo gem1.8 uninstall #{NAME}}
|
74
|
+
end
|
75
|
+
|
76
|
+
desc "Upload #{NAME} gem to rubyforge"
|
77
|
+
task :release => [:package] do
|
78
|
+
sh %{rubyforge login}
|
79
|
+
sh %{rubyforge add_release #{NAME} #{NAME} #{VERS} pkg/#{NAME}-#{VERS}.tgz}
|
80
|
+
sh %{rubyforge add_file #{NAME} #{NAME} #{VERS} pkg/#{NAME}-#{VERS}.gem}
|
81
|
+
end
|
82
|
+
|
83
|
+
require "spec/rake/spectask"
|
84
|
+
|
85
|
+
desc "Run specs with coverage"
|
86
|
+
Spec::Rake::SpecTask.new("spec") do |t|
|
87
|
+
t.spec_files = FileList["spec/*_spec.rb"]
|
88
|
+
t.spec_opts = File.read("spec/spec.opts").split("\n")
|
89
|
+
t.rcov_opts = File.read("spec/rcov.opts").split("\n")
|
90
|
+
t.rcov = true
|
91
|
+
end
|
92
|
+
|
93
|
+
desc "Run specs without coverage"
|
94
|
+
task :default => [:spec_no_cov]
|
95
|
+
Spec::Rake::SpecTask.new("spec_no_cov") do |t|
|
96
|
+
t.spec_files = FileList["spec/*_spec.rb"]
|
97
|
+
t.spec_opts = File.read("spec/spec.opts").split("\n")
|
98
|
+
end
|
99
|
+
|
100
|
+
desc "Run rcov only"
|
101
|
+
Spec::Rake::SpecTask.new("rcov") do |t|
|
102
|
+
t.rcov_opts = File.read("spec/rcov.opts").split("\n")
|
103
|
+
t.spec_opts = File.read("spec/spec.opts").split("\n")
|
104
|
+
t.spec_files = FileList["spec/*_spec.rb"]
|
105
|
+
t.rcov = true
|
106
|
+
end
|
107
|
+
|
108
|
+
desc "check documentation coverage"
|
109
|
+
task :dcov do
|
110
|
+
sh "find lib -name '*.rb' | xargs dcov"
|
111
|
+
end
|
data/lib/arpie.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
module Arpie
|
2
|
+
|
3
|
+
# A Endpoint is the server-side part of a RPC setup.
|
4
|
+
# It accepts connections (via the acceptor), and handles
|
5
|
+
# incoming RPC calls on them.
|
6
|
+
#
|
7
|
+
# There will be one Thread per connection, so order of
|
8
|
+
# execution with multiple threads is not guaranteed.
|
9
|
+
class Endpoint
|
10
|
+
|
11
|
+
# Create a new Endpoint with the given +Protocol+.
|
12
|
+
# You will need to define a handler, and an acceptor
|
13
|
+
# before the endpoint becomes operational.
|
14
|
+
def initialize protocol
|
15
|
+
@protocol = protocol
|
16
|
+
@clients = []
|
17
|
+
|
18
|
+
@handler = lambda {|endpoint, message| raise ArgumentError, "No handler defined." }
|
19
|
+
end
|
20
|
+
|
21
|
+
# Provide an acceptor; this will be run in a a loop
|
22
|
+
# to get IO objects.
|
23
|
+
#
|
24
|
+
# Example:
|
25
|
+
# listener = TCPServer.new(12345)
|
26
|
+
# my_endpoint.accept do
|
27
|
+
# listener.accept
|
28
|
+
# end
|
29
|
+
def accept &acceptor
|
30
|
+
@acceptor = acceptor
|
31
|
+
Thread.new { _acceptor_thread }
|
32
|
+
end
|
33
|
+
|
34
|
+
# Set a message handler, which is a proc that will receive
|
35
|
+
# two parameters: the endpoint, and the message.
|
36
|
+
# Its return value will be sent as the reply.
|
37
|
+
#
|
38
|
+
# Example:
|
39
|
+
# my_endpoint.handle do |endpoint, message|
|
40
|
+
# puts "Got a message: #{message.inspect}"
|
41
|
+
# "ok"
|
42
|
+
# end
|
43
|
+
def handle &handler
|
44
|
+
raise ArgumentError, "need a block" unless block_given?
|
45
|
+
@handler = handler
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def _handle message
|
51
|
+
@handler.call(self, message)
|
52
|
+
end
|
53
|
+
|
54
|
+
def _acceptor_thread
|
55
|
+
loop do
|
56
|
+
client = @acceptor.call(self)
|
57
|
+
@clients << client
|
58
|
+
Thread.new { _read_thread(client) }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def _read_thread client
|
63
|
+
loop do
|
64
|
+
break if client.eof?
|
65
|
+
|
66
|
+
message, answer = nil, nil
|
67
|
+
begin
|
68
|
+
message = @protocol.read_message(client)
|
69
|
+
rescue => e
|
70
|
+
$stderr.puts "client went away while reading the message: #{e.to_s}"
|
71
|
+
break
|
72
|
+
end
|
73
|
+
|
74
|
+
begin
|
75
|
+
answer = _handle(message)
|
76
|
+
rescue Exception => e
|
77
|
+
$stderr.puts "Error in handler: #{e.message.to_s}"
|
78
|
+
$stderr.puts e.backtrace.join("\n")
|
79
|
+
$stderr.puts "Returning exception for this call."
|
80
|
+
answer = e
|
81
|
+
end
|
82
|
+
|
83
|
+
begin
|
84
|
+
@protocol.write_message(client, answer)
|
85
|
+
rescue => e
|
86
|
+
puts "client went away while writing the answer:: #{e.to_s}"
|
87
|
+
break
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
@clients.delete(client)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Arpie
|
2
|
+
|
3
|
+
# A Protocol converts messages (which are arbitary objects)
|
4
|
+
# to a suitable on-the-wire format, and back.
|
5
|
+
class Protocol
|
6
|
+
private_class_method :new
|
7
|
+
|
8
|
+
# Read a message from +io+. Block until a message
|
9
|
+
# has been received.
|
10
|
+
def read_message io
|
11
|
+
end
|
12
|
+
|
13
|
+
# Write a message to +io+.
|
14
|
+
def write_message io, message
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# A sample binary protocol, upon which others can expand.
|
19
|
+
# The on the wire format is simply the data, prefixed
|
20
|
+
# with data.size.
|
21
|
+
class SizedProtocol < Protocol
|
22
|
+
def initialize
|
23
|
+
@max_message_size = 1024 * 1024
|
24
|
+
end
|
25
|
+
|
26
|
+
def read_message io
|
27
|
+
sz = io.read(8)
|
28
|
+
expect = sz.unpack("Q")[0]
|
29
|
+
data = io.read(expect)
|
30
|
+
end
|
31
|
+
|
32
|
+
def write_message io, message
|
33
|
+
io.write([message.size, message].pack("Qa*"))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# A procotol that simply Marshals all data sent over
|
38
|
+
# this protocol. Served as an example, but a viable
|
39
|
+
# choice for ruby-only production code.
|
40
|
+
class MarshalProtocol < SizedProtocol
|
41
|
+
public_class_method :new
|
42
|
+
|
43
|
+
def read_message io
|
44
|
+
Marshal.load super(io)
|
45
|
+
end
|
46
|
+
|
47
|
+
def write_message io, message
|
48
|
+
super io, Marshal.dump(message)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/arpie/proxy.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
module Arpie
|
2
|
+
|
3
|
+
# The RPC call encapsulation used by ProxyEndpoint and Proxy.
|
4
|
+
class ProxyCall < Struct.new(:method, :argv); end
|
5
|
+
|
6
|
+
# A Endpoint which supports arbitary objects as handlers,
|
7
|
+
# instead of a proc.
|
8
|
+
#
|
9
|
+
# Note that this will only export public instance method
|
10
|
+
# of the class as they are defined.
|
11
|
+
class ProxyEndpoint < Endpoint
|
12
|
+
def handle handler
|
13
|
+
@handler = handler
|
14
|
+
@interface = @handler.class.public_instance_methods(false)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def _handle message
|
20
|
+
@interface.index(message.method.to_s) or raise NoMethodError,
|
21
|
+
"Unknown method."
|
22
|
+
@handler.send(message.method, *message.argv)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# A Proxy is a wrapper around a transport, which transparently tunnels
|
27
|
+
# method calls to the remote ProxyEndpoint.
|
28
|
+
class Proxy
|
29
|
+
|
30
|
+
# Create a new Proxy.
|
31
|
+
def initialize transport
|
32
|
+
@transport = transport
|
33
|
+
end
|
34
|
+
|
35
|
+
def method_missing method, *argv # :nodoc:
|
36
|
+
call = ProxyCall.new(method, argv)
|
37
|
+
ret = @transport.request(call)
|
38
|
+
case ret
|
39
|
+
when Exception
|
40
|
+
raise ret
|
41
|
+
else
|
42
|
+
ret
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Arpie
|
2
|
+
|
3
|
+
# A Transport is a connection manager, and acts as the
|
4
|
+
# glue between a user-defined medium (for example, a TCP
|
5
|
+
# socket), and a protocol.
|
6
|
+
#
|
7
|
+
# See README for examples.
|
8
|
+
class Transport
|
9
|
+
attr_reader :protocol
|
10
|
+
|
11
|
+
def initialize protocol
|
12
|
+
@protocol = protocol
|
13
|
+
@io = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
# Provide a connector block, which will be called
|
17
|
+
# each time a connection is needed.
|
18
|
+
# Set +connect_immediately+ to true to connect
|
19
|
+
# immediately, instead on the first message.
|
20
|
+
def connect connect_immediately = false, &connector
|
21
|
+
@connector = connector
|
22
|
+
_connect if connect_immediately
|
23
|
+
end
|
24
|
+
|
25
|
+
# Send a message and receive a reply.
|
26
|
+
def request message
|
27
|
+
_connect
|
28
|
+
@protocol.write_message(@io, message)
|
29
|
+
@protocol.read_message(@io)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def _connect
|
34
|
+
@io ||= @connector.call(self)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/spec/rcov.opts
ADDED
File without changes
|
data/spec/spec.opts
ADDED
File without changes
|
data/tools/benchmark.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'socket'
|
3
|
+
require 'arpie'
|
4
|
+
require 'benchmark'
|
5
|
+
require 'drb'
|
6
|
+
require 'xmlrpc/server'
|
7
|
+
require 'xmlrpc/client'
|
8
|
+
|
9
|
+
class Wrap
|
10
|
+
def reverse x
|
11
|
+
x.reverse
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
include Arpie
|
16
|
+
|
17
|
+
server = TCPServer.new(51210)
|
18
|
+
|
19
|
+
endpoint = ProxyEndpoint.new MarshalProtocol.new
|
20
|
+
endpoint.handle Wrap.new
|
21
|
+
|
22
|
+
endpoint.accept do
|
23
|
+
server.accept
|
24
|
+
end
|
25
|
+
|
26
|
+
$transport = Transport.new MarshalProtocol.new
|
27
|
+
$transport.connect(false) do |transport|
|
28
|
+
TCPSocket.new("127.0.0.1", 51210)
|
29
|
+
end
|
30
|
+
$proxy = Proxy.new $transport
|
31
|
+
|
32
|
+
Benchmark.bm {|b|
|
33
|
+
|
34
|
+
puts ""
|
35
|
+
puts "native DRb"
|
36
|
+
drbserver = DRb.start_service nil, Wrap.new
|
37
|
+
drbobject = DRbObject.new nil, DRb.uri
|
38
|
+
|
39
|
+
b.report(" 1") { 1.times { drbobject.reverse "benchmark" } }
|
40
|
+
b.report("1000") { 1000.times { drbobject.reverse "benchmark" } }
|
41
|
+
|
42
|
+
puts ""
|
43
|
+
puts "ruby xmlrpc/server - too slow to benchmark"
|
44
|
+
#server = XMLRPC::Server.new(51211, "127.0.0.1", 4, nil, false)
|
45
|
+
#server.add_handler(XMLRPC::iPIMethods("wrap"), Wrap.new)
|
46
|
+
#server_thread = Thread.new { server.serve }
|
47
|
+
#client = XMLRPC::Client.new( "127.0.0.1", "/", 51211)
|
48
|
+
#b.report(" 1") { 1.times { client.call("wrap.reverse", "benchmark") } }
|
49
|
+
#b.report("1000") { 1000.times { client.call("wrap.reverse", "benchmark") } }
|
50
|
+
#server.shutdown
|
51
|
+
#server_thread.join
|
52
|
+
|
53
|
+
puts ""
|
54
|
+
puts "Arpie: proxied MarshalProtocol"
|
55
|
+
b.report(" 1") { 1.times { $proxy.reverse "benchmark" } }
|
56
|
+
b.report("1000") { 1000.times { $proxy.reverse "benchmark" } }
|
57
|
+
}
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: arpie
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bernhard Stoeckner
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-01-18 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: a synchronous RPC library based on google protobuf
|
17
|
+
email: elven@swordcoast.net
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
- COPYING
|
25
|
+
files:
|
26
|
+
- COPYING
|
27
|
+
- README
|
28
|
+
- Rakefile
|
29
|
+
- spec/spec.opts
|
30
|
+
- spec/rcov.opts
|
31
|
+
- lib/arpie.rb
|
32
|
+
- lib/arpie
|
33
|
+
- lib/arpie/protocol.rb
|
34
|
+
- lib/arpie/transport.rb
|
35
|
+
- lib/arpie/endpoint.rb
|
36
|
+
- lib/arpie/proxy.rb
|
37
|
+
- tools/benchmark.rb
|
38
|
+
has_rdoc: true
|
39
|
+
homepage: http://arpie.elv.es
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options:
|
42
|
+
- --quiet
|
43
|
+
- --line-numbers
|
44
|
+
- --inline-source
|
45
|
+
- --title
|
46
|
+
- "arpie: A high-performing layered RPC framework. Simple to use, simple to extend."
|
47
|
+
- --main
|
48
|
+
- README
|
49
|
+
- --exclude
|
50
|
+
- ^(examples|extras)/
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 1.8.4
|
58
|
+
version:
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project: arpie
|
68
|
+
rubygems_version: 1.3.0
|
69
|
+
signing_key:
|
70
|
+
specification_version: 2
|
71
|
+
summary: a synchronous RPC library based on google protobuf
|
72
|
+
test_files: []
|
73
|
+
|